diff --git a/frontend/.browserslistrc b/frontend/.browserslistrc deleted file mode 100644 index 4f9ac269..00000000 --- a/frontend/.browserslistrc +++ /dev/null @@ -1,16 +0,0 @@ -# This file is used by the build system to adjust CSS and JS output to support the specified browsers below. -# For additional information regarding the format and rule options, please see: -# https://github.com/browserslist/browserslist#queries - -# For the full list of supported browsers by the Angular framework, please see: -# https://angular.io/guide/browser-support - -# You can see what browsers were selected by your queries by running: -# npx browserslist - -last 1 Chrome version -last 1 Firefox version -last 2 Edge major versions -last 2 Safari major versions -last 2 iOS major versions -Firefox ESR diff --git a/frontend/.editorconfig b/frontend/.editorconfig deleted file mode 100644 index 47510e92..00000000 --- a/frontend/.editorconfig +++ /dev/null @@ -1,18 +0,0 @@ -# Editor configuration, see https://editorconfig.org -root = true - -[*] -charset = utf-8 -indent_style = space -indent_size = 2 -insert_final_newline = true -trim_trailing_whitespace = true -end_of_line = lf -max_line_length = 120 - -[*.ts] -quote_type = single - -[*.md] -max_line_length = off -trim_trailing_whitespace = false diff --git a/frontend/.eslintrc.json b/frontend/.eslintrc.json deleted file mode 100644 index af78e043..00000000 --- a/frontend/.eslintrc.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "root": true, - "ignorePatterns": ["projects/**/*"], - "overrides": [ - { - "files": ["*.ts"], - "parserOptions": { - "project": ["tsconfig.json"], - "createDefaultProgram": true - }, - "extends": ["plugin:@angular-eslint/recommended", "plugin:@angular-eslint/template/process-inline-templates"], - "rules": { - "@angular-eslint/directive-selector": [ - "error", - { - "type": "attribute", - "prefix": "app", - "style": "camelCase" - } - ], - "@angular-eslint/component-selector": [ - "error", - { - "type": "element", - "prefix": "app", - "style": "kebab-case" - } - ], - "@angular-eslint/no-empty-lifecycle-method": "off" - } - }, - { - "files": ["*.html"], - "extends": ["plugin:@angular-eslint/template/recommended"], - "rules": {} - } - ] -} diff --git a/frontend/.gitignore b/frontend/.gitignore index e0232ece..f558a1cc 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -1,73 +1 @@ -# See http://help.github.com/ignore-files/ for more about ignoring files. - -# Compiled output -/dist -/tmp -/out-tsc -# Only exists if Bazel was run -/bazel-out - -# Dependencies -/node_modules - -reports/ - -# Cordova -/www -/plugins -/platforms - -# Electron -/dist-electron -/dist-packages -/electron.main.js - -# IDEs and editors -.idea/* -!.idea/runConfigurations/ -!.idea/codeStyleSettings.xml -.project -.classpath -.c9/ -*.launch -.settings/ -xcuserdata/ -*.sublime-workspace - -# IDE - VSCode -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json - -# Maven -/target -/log - -# Misc -/.angular/cache -/.sass-cache -/connect.lock -/coverage -/libpeerconnection.log -npm-debug.log -yarn-error.log -testem.log -/typings -/reports -/src/translations/template.* -/src/environments/.env.* -/cypress/videos/ - -# System Files -.DS_Store -Thumbs.db -.aider* - -/.venv/* -/.venv/ -.venv - -# Pyodide-related files -/pyodide/ +.angular \ No newline at end of file diff --git a/frontend/.npmrc b/frontend/.npmrc deleted file mode 100644 index 5660f81a..00000000 --- a/frontend/.npmrc +++ /dev/null @@ -1 +0,0 @@ -registry=https://registry.npmjs.org/ \ No newline at end of file diff --git a/frontend/.nvmrc b/frontend/.nvmrc deleted file mode 100644 index d5908b99..00000000 --- a/frontend/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -20.12 \ No newline at end of file diff --git a/frontend/.prettierignore b/frontend/.prettierignore deleted file mode 100644 index 2c4bb863..00000000 --- a/frontend/.prettierignore +++ /dev/null @@ -1 +0,0 @@ -src/environments/.env.ts diff --git a/frontend/.python-version b/frontend/.python-version deleted file mode 100644 index 82920a35..00000000 --- a/frontend/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.11.7 \ No newline at end of file diff --git a/frontend/.stylelintrc b/frontend/.stylelintrc deleted file mode 100644 index 0718186c..00000000 --- a/frontend/.stylelintrc +++ /dev/null @@ -1,46 +0,0 @@ -{ - "extends": ["stylelint-config-standard", "stylelint-config-recommended-scss", "stylelint-config-prettier"], - "rules": { - "font-family-name-quotes": "always-where-recommended", - "function-url-quotes": [ - "always", - { - "except": ["empty"] - } - ], - "selector-attribute-quotes": "always", - "string-quotes": "double", - "max-nesting-depth": 3, - "selector-max-compound-selectors": 3, - "selector-max-specificity": "0,3,2", - "declaration-no-important": true, - "at-rule-no-vendor-prefix": true, - "media-feature-name-no-vendor-prefix": true, - "property-no-vendor-prefix": true, - "selector-no-vendor-prefix": true, - "value-no-vendor-prefix": true, - "no-empty-source": null, - "selector-class-pattern": "[a-z-]+", - "selector-id-pattern": "[a-z-]+", - "selector-max-id": 0, - "selector-no-qualifying-type": true, - "selector-max-universal": 0, - "selector-type-no-unknown": [ - true, - { - "ignore": ["custom-elements", "default-namespace"] - } - ], - "selector-pseudo-element-no-unknown": [ - true, - { - "ignorePseudoElements": ["ng-deep"] - } - ], - "unit-allowed-list": ["px", "%", "em", "rem", "vw", "vh", "deg", "s"], - "max-empty-lines": 2, - "max-line-length": 120, - "no-invalid-position-at-import-rule": null, - "scss/comment-no-empty": null - } -} diff --git a/frontend/.yo-rc.json b/frontend/.yo-rc.json deleted file mode 100644 index 76e022bc..00000000 --- a/frontend/.yo-rc.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "generator-ngx-rocket": { - "version": "11.0.0", - "props": { - "location": "path", - "strict": true, - "skipInstall": false, - "skipQuickstart": false, - "initGit": true, - "usePrefix": true, - "appName": "sophia-ng", - "target": ["web"], - "ui": "material", - "layout": "side-menu", - "features": ["auth", "lazy", "cypress"], - "languages": ["en-US"], - "tools": ["prettier", "hads", "jest"], - "utility": ["lodash", "datefns"], - "deploy": "firebase", - "projectName": "sophia-ng", - "packageManager": "npm", - "mobile": [], - "desktop": [], - "pwa": false, - "auth": true, - "lazy": true, - "e2e": false, - "cypress": true, - "angulartics": false - } - } -} diff --git a/frontend/AI.md b/frontend/AI.md deleted file mode 100644 index 6c4a075b..00000000 --- a/frontend/AI.md +++ /dev/null @@ -1,3 +0,0 @@ -When adding a new top level component -- Add the route to src/app/app-routing.module.ts -- Add the menu item in src/app/shell/shell.component.html diff --git a/frontend/CREDITS b/frontend/CREDITS new file mode 100644 index 00000000..6fef4f16 --- /dev/null +++ b/frontend/CREDITS @@ -0,0 +1,72 @@ +// ----------------------------------------------------------------------------------------------------- +// @ 3rd party credits +// ----------------------------------------------------------------------------------------------------- + +// Flags +https://github.com/Yummygum/flagpack-core + +// Icons +Material - https://material.io/tools/icons +Feather - https://feathericons.com/ +Heroicons - https://github.com/refactoringui/heroicons +Iconsmind - https://iconsmind.com/ + +// Avatars +https://uifaces.co + +// 404, 500 & Maintenance +https://undraw.co + +// Mail app +Photo by Riccardo Chiarini on Unsplash - https://unsplash.com/photos/2VDa8bnLM8c +Photo by Johannes Plenio on Unsplash - https://unsplash.com/photos/RwHv7LgeC7s +Photo by Jamie Davies on Unsplash - https://unsplash.com/photos/Hao52Fu9-F8 +Photo by Christian Joudrey on Unsplash - https://unsplash.com/photos/mWRR1xj95hg + +// Profile page +Photo by Alex Knight on Unsplash - https://unsplash.com/photos/DpPutJwgyW8 + +// Cards +Photo by Kym Ellis on Unsplash - https://unsplash.com/photos/RPT3AjdXlZc +Photo by Patrick Hendry on Unsplash - https://unsplash.com/photos/Qgxk3PQsMiI +Photo by Hailey Kean on Unsplash - https://unsplash.com/photos/QxjsOlFNr_4 +Photo by Nathan Anderson on Unsplash - https://unsplash.com/photos/mG8ShlWrMDI +Photo by Adrian Infernus on Unsplash - https://unsplash.com/photos/5apewqWk978 +Photo by freestocks.org on Unsplash - https://unsplash.com/photos/c73TZ2sIU38 +Photo by Tim Marshall on Unsplash - https://unsplash.com/photos/PKSCrmZdvwA +Photo by Daniel Koponyas on Unsplash - https://unsplash.com/photos/rbiLY6ZwvXQ +Photo by John Westrock on Unsplash - https://unsplash.com/photos/LCesauDseu8 +Photo by Gabriel Sollmann on Unsplash - https://unsplash.com/photos/kFWj9y-tJB4 +Photo by Kevin Wolf on Unsplash - https://unsplash.com/photos/BJyjgEdNTPs +Photo by Luca Bravo on Unsplash - https://unsplash.com/photos/hFzIoD0F_i8 +Photo by Ian Baldwin on Unsplash - https://unsplash.com/photos/Dlj-SxxTlQ0 +Photo by Ben Kolde on Unsplash - https://unsplash.com/photos/KRTFIBOfcFw +Photo by Chad Peltola on Unsplash - https://unsplash.com/photos/BTvQ2ET_iKc +Photo by rocknwool on Unsplash - https://unsplash.com/photos/r56oO1V5oms +Photo by Vita Vilcina on Unsplash - https://unsplash.com/photos/KtOid0FLjqU +Photo by Jia Ye on Unsplash - https://unsplash.com/photos/y8ZnQqgohLk +Photo by Parker Whitson on Unsplash - https://unsplash.com/photos/OlTYIqTjmVM +Photo by Dorian Hurst on Unsplash - https://unsplash.com/photos/a9uWPQlIbYc +Photo by Everaldo Coelho on Unsplash - https://unsplash.com/photos/KPaSCpklCZw +Photo by eberhard grossgasteiger on Unsplash - https://unsplash.com/photos/fh2JefbNlII +Photo by Orlova Maria on Unsplash - https://unsplash.com/photos/p8y4dWEMGMU +Photo by Jake Blucker on Unsplash - https://unsplash.com/photos/tMzCrBkM99Y +Photo by Jerry Zhang on Unsplash - https://unsplash.com/photos/oIBcow6n36s +Photo by John Cobb on Unsplash - https://unsplash.com/photos/IE_sifhay7o +Photo by Dan Gold on Unsplash - https://unsplash.com/photos/mDlhOIfGxNI +Photo by Ana Toma on Unsplash - https://unsplash.com/photos/XsGwe6gYg0c +Photo by Andrea on Unsplash - https://unsplash.com/photos/1AWY0N960Sk +Photo by Aswin on Unsplash - https://unsplash.com/photos/_roUcFWstas +Photo by Justin Kauffman on Unsplash - https://unsplash.com/photos/aWG_dqyhI0A +Photo by Barna Bartis on Unsplash - https://unsplash.com/photos/VVoBQqWrvkc +Photo by Kyle Hinkson on Unsplash - https://unsplash.com/photos/3439EnvnAGo +Photo by Spencer Watson on Unsplash - https://unsplash.com/photos/5TBf16GnHKg +Photo by adrian on Unsplash - https://unsplash.com/photos/1wrzvwoK8A4 +Photo by Christopher Rusev on Unsplash - https://unsplash.com/photos/7gKWgCRixf0 +Photo by Stephen Leonardi on Unsplash - https://unsplash.com/photos/MDmwQVgDHHM +Photo by Dwinanda Nurhanif Mujito on Unsplash - https://unsplash.com/photos/pKT5Mg16w_w +Photo by Humphrey Muleba on Unsplash - https://unsplash.com/photos/Zuvf5mxT5fs +Photo by adrian on Unsplash - https://unsplash.com/photos/PNRxLFPMyJY +Photo by Dahee Son on Unsplash - https://unsplash.com/photos/tV06QVJXVxU +Photo by Zachary Kyra-Derksen on Unsplash - https://unsplash.com/photos/vkqS7vLQUtg +Photo by Rodrigo Soares on Unsplash - https://unsplash.com/photos/8BFWBUkSqQo diff --git a/frontend/DOCS.md b/frontend/DOCS.md new file mode 100644 index 00000000..192f78a7 --- /dev/null +++ b/frontend/DOCS.md @@ -0,0 +1,118 @@ +Fuse built around the idea of multi-purpose and multi-layout. You can think of Fuse as a Starter kit and a guide rather than just a simple template. The purpose of Fuse is not only provide a pre-made styles for visual elements but is also be a guide to follow while building an app. + +It's more of an answer to the questions like Where should I put this file? or Which file should I put this piece of code into? rather than just a compilation of example pages and ready to use styles. + +Here's a simplified version of the entire directory structure of the Fuse: + +public +src/ +@fuse/ +app/ +styles/ +├─ +index.html +└─ +main.ts +/public +Default folder for static assets like images, fonts, static styles and etc. + +/src/@fuse/ +This is the core directory of the Fuse. It includes components, directives, services, pipes, custom validators, animations, base styles and much more. + +Modifications on this directory is NOT recommended. Since majority of changes happen within this directory on updates, any modifications to this directory and its content will make the updating process complex and time consuming. + +src/app/ +This directory contains all application related codes. This is where you put your code. + +Fuse provides a sensible default directory structure within the app directory. You can of course completely remove everything from it and design your own structure but the provided structure is designed to handle applications from small to enterprise grade: + +app/ +core/ +layout/ +mock-api/ +modules/ +├─ +app.component.html +├─ +app.component.scss +├─ +app.component.ts +├─ +app.config.ts +├─ +app.resolvers.ts +└─ +app.routes.ts +src/app/core/ +This directory is designed to contain your application's core; Singleton services, default configurations, default states and likes. It's NOT recommended to put any components, directives, pipes or simply anything has a template or related to templates in here. + +Example files that can go into this directory includes, but not limited to: + +Singleton services: + +Auth service + +Logger service + +SplashScreen service + +Guards + +Auth guard + +NoAuth guard + +Defaults + +Default configurations + +Default state + +Custom validators + +Phone number validator + +Confirm validator + +and etc... + +src/app/mock-api/ +This directory is designed to contain data services for custom made MockAPI library. Detailed information about this directory and the MockAPI library can be found in the Fuse Components > Libraries > MockAPI section of this documentation. + +src/app/layout/ +This directory designed to contain everything related to the layout of your app. By default, Fuse provides variety of different layout options for you to use. + +The LayoutComponent is an entry component and it provides an easy way of switching between different layouts. More information about how the LayoutComponent works can be found in the Customization > Theme layouts section of this documentation. + +The app/layout/common/ folder includes common components for layouts such as: + +Messages +Notifications +Search +Shortcuts +User Menu +These components are being used across different layouts, so if you use multiple layouts and want to create a component, directive or a pipe for using within your layouts, you can put them inside the common folder. + +src/app/modules/ +This directory is designed to contain your application's feature modules. + +For example; Authentication related pages such as Sign In, Sign Up, Lost Password and etc. can be grouped into auth/ directory while your main admin components and modules grouped into admin/ directory. + +If you use SSR (Server Side Rendering) you can even include your landing page as one of the modules and keep everything in a single app. + +src/styles/ +This folder contains 4 different scss files: + +styles.scss + +This file is for adding/importing global styles to the app. + +tailwind.scss + +This is the main Tailwind file for Tailwind utilities. + +vendors.scss + +This file is designed to import 3rd party library css/scss files into the project. Any style here can be overridden by styles.scss file allowing you to overwrite/modify 3rd party library styles and make them visually compatible with your app. + +For example, let's say you use FullCalendar 3rd party library. You use the vendors.scss file to import default styles of the FullCalendar into your project so it looks and works correctly. Then, you can add custom styles to the styles.scss file to overwrite those default styles to make FullCalendar compatible with your app's design. \ No newline at end of file diff --git a/frontend/LICENSE.md b/frontend/LICENSE.md new file mode 100644 index 00000000..2f43b953 --- /dev/null +++ b/frontend/LICENSE.md @@ -0,0 +1,19 @@ +Envato Standard License + +Copyright (c) Withinpixels + +This project is protected by Envato's Standard License. For more information, +check the official license page at [https://themeforest.net/licenses/standard](https://themeforest.net/licenses/standard) + + +The Fuse team have generously allowed their very high quality template to be used for the open-source Sophia frontend. + +You may customise the Sophia project UI for your personal use. + +You may not remove the Sophia functionality and use the UI template for another purpose. + +If you want to make extensive customisations, or use the template for another purpose, +you can purchase the full template with all the sample screens and functionality for a very reasonable $29. + +https://fusetheme.com/admin-templates/angular/ +https://themeforest.net/item/fuse-angularjs-material-design-admin-template/12931855 diff --git a/frontend/README.md b/frontend/README.md index cf775765..b8664879 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -1,151 +1,27 @@ -# sophia-ng +# Fuse - Admin template and Starter project for Angular -This project was generated with [ngX-Rocket](https://github.com/ngx-rocket/generator-ngx-rocket/) -version 11.0.0 - -# Getting started - -1. Go to project folder and install dependencies: - -```sh -npm install -``` - -2. Launch development server, and open `localhost:4200` in your browser: - -```sh -npm start -``` - -# Project structure - -``` -dist/ web app production build -docs/ project docs and coding guides -cypress/ end-to-end tests (Cypress) -src/ project source code -|- app/ app components -| |- core/ core module (singleton services and single-use components) -| |- shared/ shared module (common components, directives and pipes) -| |- app.component.* app root component (shell) -| |- app.module.ts app root module definition -| |- app-routing.module.ts app routes -| +- ... additional modules and components -|- assets/ app assets (images, fonts, sounds...) -|- environments/ values for various build environments -|- theme/ app global scss variables and theme -|- translations/ translations files -|- index.html html entry point -|- main.scss global style entry point -|- main.ts app entry point -|- polyfills.ts polyfills needed by Angular -+- setup-jest.ts unit tests entry point -reports/ test and coverage reports -proxy.conf.js backend proxy configuration -``` - -# Main tasks - -Task automation is based on [NPM scripts](https://docs.npmjs.com/misc/scripts). - -| Task | Description | -| ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | -| `npm start` | Run development server on `http://localhost:4200/` | -| `npm run build [-- --configuration=production]` | Lint code and build web app for production (with [AOT](https://angular.io/guide/aot-compiler)) in `dist/` folder | -| `npm test` | Run unit tests via [Karma](https://karma-runner.github.io) in watch mode | -| `npm run test:ci` | Lint code and run unit tests once for continuous integration | -| `npm run e2e` | Run e2e tests using [Cypress](https://www.cypress.io/) | -| `npm run lint` | Lint code | -| `npm run translations:extract` | Extract strings from code and templates to `src/app/translations/template.json` | -| `npm run docs` | Display project documentation and coding guides | -| `npm run prettier` | Automatically format all `.ts`, `.js` & `.scss` files | - -When building the application, you can specify the target configuration using the additional flag -`--configuration ` (do not forget to prepend `--` to pass arguments to npm scripts). - -The default build configuration is `prod`. - -## Configuration - -For deployed builds set the SERVER_URL environment variable to the backend API server URL before running `npm run build` - -The path the UI is served at is set in the package.json `build` script and has been set to `/ui/`. +This project was generated with [Angular CLI](https://github.com/angular/angular-cli) ## Development server -Run `npm start` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change -any of the source files. -You should not use `ng serve` directly, as it does not use the backend proxy configuration by default. +Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. ## Code scaffolding -Run `npm run generate -- component ` to generate a new component. You can also use -`npm run generate -- directive|pipe|service|class|module`. - -If you have installed [angular-cli](https://github.com/angular/angular-cli) globally with `npm install -g @angular/cli`, -you can also use the command `ng generate` directly. - -## Additional tools - -Tasks are mostly based on the `angular-cli` tool. Use `ng help` to get more help or go check out the -[Angular-CLI README](https://github.com/angular/angular-cli). - -## Code formatting - -All `.ts`, `.js` & `.scss` files in this project are formatted automatically using [Prettier](https://prettier.io), -and enforced via the `test:ci` script. - -A pre-commit git hook has been configured on this project to automatically format staged files, using -(pretty-quick)[https://github.com/azz/pretty-quick], so you don't have to care for it. - -You can also force code formatting by running the command `npm run prettier`. - -# What's in the box - -The app template is based on [HTML5](http://whatwg.org/html), [TypeScript](http://www.typescriptlang.org) and -[Sass](http://sass-lang.com). The translation files use the common [JSON](http://www.json.org) format. - -#### Tools +Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. -Development, build and quality processes are based on [angular-cli](https://github.com/angular/angular-cli) and -[NPM scripts](https://docs.npmjs.com/misc/scripts), which includes: +## Build -- Optimized build and bundling process with [Webpack](https://webpack.github.io) -- [Development server](https://webpack.github.io/docs/webpack-dev-server.html) with backend proxy and live reload -- Cross-browser CSS with [autoprefixer](https://github.com/postcss/autoprefixer) and - [browserslist](https://github.com/ai/browserslist) -- Asset revisioning for [better cache management](https://webpack.github.io/docs/long-term-caching.html) -- Unit tests using [Jasmine](http://jasmine.github.io) and [Karma](https://karma-runner.github.io) -- End-to-end tests using [Cypress](https://www.cypress.io/) -- Static code analysis: [TSLint](https://github.com/palantir/tslint), [Codelyzer](https://github.com/mgechev/codelyzer), - [Stylelint](http://stylelint.io) and [HTMLHint](http://htmlhint.com/) -- Local knowledgebase server using [Hads](https://github.com/sinedied/hads) -- Automatic code formatting with [Prettier](https://prettier.io) +Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. -#### Libraries +## Running unit tests -- [Angular](https://angular.io) -- [Angular Material](https://material.angular.io) -- [Angular Flex Layout](https://github.com/angular/flex-layout) -- [Material Icons](https://material.io/icons/) -- [RxJS](http://reactivex.io/rxjs) -- [ngx-translate](https://github.com/ngx-translate/core) -- [Lodash](https://lodash.com) -- [Date-fns](https://date-fns.org) +Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). -#### Coding guides +## Running end-to-end tests -- [Angular](docs/coding-guides/angular.md) -- [TypeScript](docs/coding-guides/typescript.md) -- [Sass](docs/coding-guides/sass.md) -- [HTML](docs/coding-guides/html.md) -- [Unit tests](docs/coding-guides/unit-tests.md) -- [End-to-end tests](docs/coding-guides/e2e-tests.md) +Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. -#### Other documentation +## Further help -- [I18n guide](docs/i18n.md) -- [Working behind a corporate proxy](docs/corporate-proxy.md) -- [Updating dependencies and tools](docs/updating.md) -- [Using a backend proxy for development](docs/backend-proxy.md) -- [Browser routing](docs/routing.md) +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. diff --git a/frontend/angular.json b/frontend/angular.json index 9fdd93c6..9b369998 100644 --- a/frontend/angular.json +++ b/frontend/angular.json @@ -3,14 +3,11 @@ "version": 1, "newProjectRoot": "projects", "projects": { - "sophia-ng": { + "fuse": { "projectType": "application", "schematics": { "@schematics/angular:component": { "style": "scss" - }, - "@schematics/angular:application": { - "strict": true } }, "root": "", @@ -18,16 +15,47 @@ "prefix": "app", "architect": { "build": { - "builder": "@angular-devkit/build-angular:browser", + "builder": "@angular-devkit/build-angular:application", "options": { - "outputPath": "dist", + "outputPath": "dist/fuse", "index": "src/index.html", - "main": "src/main.ts", - "polyfills": "src/polyfills.ts", + "browser": "src/main.ts", + "polyfills": [ + "zone.js" + ], "tsConfig": "tsconfig.app.json", "inlineStyleLanguage": "scss", - "assets": ["src/favicon.ico", "src/apple-touch-icon.png", "src/robots.txt", "src/assets"], - "styles": ["src/main.scss"], + "allowedCommonJsDependencies": [ + "apexcharts", + "crypto-js/enc-utf8", + "crypto-js/hmac-sha256", + "crypto-js/enc-base64", + "quill-delta" + ], + "assets": [ + { + "glob": "**/*", + "input": "public" + }, + { + "glob": "_redirects", + "input": "src", + "output": "/" + } + ], + "stylePreprocessorOptions": { + "includePaths": [ + "src/@fuse/styles" + ] + }, + "styles": [ + "src/@fuse/styles/tailwind.scss", + "src/@fuse/styles/themes.scss", + "src/styles/vendors.scss", + "src/@fuse/styles/main.scss", + "src/styles/styles.scss", + "src/styles/tailwind.scss" + ], "scripts": [] }, "configurations": { @@ -35,33 +63,33 @@ "budgets": [ { "type": "initial", - "maximumWarning": "2mb", + "maximumWarning": "3mb", "maximumError": "5mb" }, { "type": "anyComponentStyle", - "maximumWarning": "6kb", - "maximumError": "10kb" + "maximumWarning": "75kb", + "maximumError": "90kb" } ], + "outputHashing": "all", "fileReplacements": [ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.prod.ts" } - ], - "outputHashing": "all" + ] }, "development": { - "buildOptimizer": false, "optimization": false, - "vendorChunk": true, "extractLicenses": false, "sourceMap": true, - "namedChunks": true - }, - "ci": { - "progress": false + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.ts" + } + ] } }, "defaultConfiguration": "production" @@ -70,77 +98,54 @@ "builder": "@angular-devkit/build-angular:dev-server", "configurations": { "production": { - "browserTarget": "sophia-ng:build:production" + "buildTarget": "fuse:build:production" }, "development": { - "browserTarget": "sophia-ng:build:development" - }, - "ci": { - "progress": false + "buildTarget": "fuse:build:development" } }, "defaultConfiguration": "development" }, "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", - "options": { - "browserTarget": "sophia-ng:build" - } + "builder": "@angular-devkit/build-angular:extract-i18n" }, "test": { - "builder": "@angular-builders/jest:run", + "builder": "@angular-devkit/build-angular:karma", "options": { - "watch": true - }, - "configurations": { - "ci": { - "watch": false, - "ci": true, - "coverage": true, - "silent": true - } + "polyfills": [ + "zone.js", + "zone.js/testing" + ], + "tsConfig": "tsconfig.spec.json", + "inlineStyleLanguage": "scss", + "assets": [ + { + "glob": "**/*", + "input": "public" + } + ], + "styles": [ + "src/styles/styles.scss" + ], + "scripts": [] } }, "lint": { "builder": "@angular-eslint/builder:lint", "options": { - "lintFilePatterns": ["src/**/*.ts", "src/**/*.html"] - } - }, - "cypress-run": { - "builder": "@cypress/schematic:cypress", - "options": { - "devServerTarget": "sophia-ng:serve" - }, - "configurations": { - "production": { - "devServerTarget": "sophia-ng:serve:production" - } - } - }, - "cypress-open": { - "builder": "@cypress/schematic:cypress", - "options": { - "watch": true, - "headless": false - } - }, - "e2e": { - "builder": "@cypress/schematic:cypress", - "options": { - "devServerTarget": "sophia-ng:serve" - }, - "configurations": { - "production": { - "devServerTarget": "sophia-ng:serve:production" - } + "lintFilePatterns": [ + "src/**/*.ts", + "src/**/*.html" + ] } } } } }, - "defaultProject": "sophia-ng", "cli": { - "analytics": false + "analytics": "a688e248-487b-480b-869c-cdc5401886c6", + "schematicCollections": [ + "@angular-eslint/schematics" + ] } } diff --git a/frontend/bin/configure b/frontend/bin/configure deleted file mode 100644 index 0eecbd98..00000000 --- a/frontend/bin/configure +++ /dev/null @@ -1,22 +0,0 @@ - - -# Python setup ------------------------ -# pyenv install $(cat .python-version) - -[[ -n $VIRTUAL_ENV ]] || VIRTUAL_ENV="$(pwd)/.venv" -if [[ -d "$VIRTUAL_ENV" ]]; then - echo "Activating python virtual environment" - source ./.venv/bin/activate -else - echo "Creating python virtual environment" - python3 -m venv .venv - source ./.venv/bin/activate - python -m pip install --upgrade pip - pip install aider-chat -fi - -# Node.js setup ------------------------ - -#nvm install $(cat .nvmrc) -nvm use -#npm install diff --git a/frontend/bin/openai b/frontend/bin/openai deleted file mode 100644 index 34f11948..00000000 --- a/frontend/bin/openai +++ /dev/null @@ -1 +0,0 @@ -export OPENAI_API_KEY=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 \ No newline at end of file diff --git a/frontend/bin/run b/frontend/bin/run deleted file mode 100755 index e7a7e010..00000000 --- a/frontend/bin/run +++ /dev/null @@ -1,3 +0,0 @@ -#/bin/bash -mkdir -p ~/.config/gcloud -docker-compose up --build diff --git a/frontend/cypress.config.ts b/frontend/cypress.config.ts deleted file mode 100644 index 672370c7..00000000 --- a/frontend/cypress.config.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { defineConfig } from 'cypress'; - -export default defineConfig({ - videosFolder: 'cypress/videos', - screenshotsFolder: 'cypress/screenshots', - fixturesFolder: 'cypress/fixtures', - e2e: { - // We've imported your old cypress plugins here. - // You may want to clean this up later by importing these. - setupNodeEvents(on, config) { - return require('./cypress/plugins/index.ts')(on, config); - }, - baseUrl: 'http://localhost:4200', - excludeSpecPattern: ['**/*.po.ts'], - }, -}); diff --git a/frontend/cypress/e2e/app.cy.ts b/frontend/cypress/e2e/app.cy.ts deleted file mode 100644 index 9fc02277..00000000 --- a/frontend/cypress/e2e/app.cy.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { LoginPage } from './page-objects/login.po'; -import { AppSharedPage } from './page-objects/app-shared.po'; -import { HomePage } from './page-objects/home.po'; - -describe('when the app loads', () => { - const login = new LoginPage(); - const app = new AppSharedPage(); - const home = new HomePage(); - - before(() => { - app.navigateAndSetLanguage(); - }); - - it('should display the login page and log in', () => { - cy.url().should('include', login.url); - login.login(); - }); - - it('should display the home page and say hello', () => { - cy.url().should('include', home.url); - home.welcomeText.contains('Hello world !'); - }); -}); diff --git a/frontend/cypress/e2e/page-objects/app-shared.po.ts b/frontend/cypress/e2e/page-objects/app-shared.po.ts deleted file mode 100644 index ac8f13ad..00000000 --- a/frontend/cypress/e2e/page-objects/app-shared.po.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Use the Page Object pattern to define the page under test. - * See docs/coding-guide/e2e-tests.md for more info. - */ - -export class AppSharedPage { - async navigateAndSetLanguage() { - // Forces default language - this.visit(); - cy.window().then((window) => { - window.eval(`localStorage.setItem('language', 'en-US')`); - }); - } - - visit() { - cy.visit('/'); - } -} diff --git a/frontend/cypress/e2e/page-objects/home.po.ts b/frontend/cypress/e2e/page-objects/home.po.ts deleted file mode 100644 index c5400f66..00000000 --- a/frontend/cypress/e2e/page-objects/home.po.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Use the Page Object pattern to define the page under test. - * See docs/coding-guide/e2e-tests.md for more info. - */ - -export class HomePage { - url = '/home'; - - get welcomeText() { - return cy.get('app-root mat-card-title'); - } -} diff --git a/frontend/cypress/e2e/page-objects/login.po.ts b/frontend/cypress/e2e/page-objects/login.po.ts deleted file mode 100644 index 19513a08..00000000 --- a/frontend/cypress/e2e/page-objects/login.po.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Use the Page Object pattern to define the page under test. - * See docs/coding-guide/e2e-tests.md for more info. - */ - -export class LoginPage { - url = '/login'; - - get usernameField() { - return cy.get('[formControlName="username"]'); - } - - get passwordField() { - return cy.get('[formcontrolname="password"]'); - } - - get loginButton() { - return cy.get('[type="submit"]'); - } - - login() { - this.usernameField.type('test'); - this.passwordField.type('123'); - this.loginButton.click(); - } -} diff --git a/frontend/cypress/fixtures/example.json b/frontend/cypress/fixtures/example.json deleted file mode 100644 index 02e42543..00000000 --- a/frontend/cypress/fixtures/example.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "Using fixtures to represent data", - "email": "hello@cypress.io", - "body": "Fixtures are a great way to mock data for responses to routes" -} diff --git a/frontend/cypress/plugins/index.ts b/frontend/cypress/plugins/index.ts deleted file mode 100644 index edf74d31..00000000 --- a/frontend/cypress/plugins/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -// Plugins enable you to tap into, modify, or extend the internal behavior of Cypress -// For more info, visit https://on.cypress.io/plugins-api -module.exports = (on, config) => {}; diff --git a/frontend/cypress/support/commands.ts b/frontend/cypress/support/commands.ts deleted file mode 100644 index af1f44a0..00000000 --- a/frontend/cypress/support/commands.ts +++ /dev/null @@ -1,43 +0,0 @@ -// *********************************************** -// This example namespace declaration will help -// with Intellisense and code completion in your -// IDE or Text Editor. -// *********************************************** -// declare namespace Cypress { -// interface Chainable { -// customCommand(param: any): typeof customCommand; -// } -// } -// -// function customCommand(param: any): void { -// console.warn(param); -// } -// -// NOTE: You can use it like so: -// Cypress.Commands.add('customCommand', customCommand); -// -// *********************************************** -// This example commands.js shows you how to -// create various custom commands and overwrite -// existing commands. -// -// For more comprehensive examples of custom -// commands please read more here: -// https://on.cypress.io/custom-commands -// *********************************************** -// -// -// -- This is a parent command -- -// Cypress.Commands.add("login", (email, password) => { ... }) -// -// -// -- This is a child command -- -// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) -// -// -// -- This is a dual command -- -// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) -// -// -// -- This will overwrite an existing command -- -// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) diff --git a/frontend/cypress/support/e2e.ts b/frontend/cypress/support/e2e.ts deleted file mode 100644 index ac293b61..00000000 --- a/frontend/cypress/support/e2e.ts +++ /dev/null @@ -1,17 +0,0 @@ -// *********************************************************** -// This example support/index.js is processed and -// loaded automatically before your test files. -// -// This is a great place to put global configuration and -// behavior that modifies Cypress. -// -// You can change the location of this file or turn off -// automatically serving support files with the -// 'supportFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/configuration -// *********************************************************** - -// When a command from ./commands is ready to use, import with `import './commands'` syntax -// import './commands'; diff --git a/frontend/cypress/tsconfig.json b/frontend/cypress/tsconfig.json deleted file mode 100644 index 79d78d7e..00000000 --- a/frontend/cypress/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "../tsconfig.json", - "include": ["**/*.ts"], - "compilerOptions": { - "sourceMap": false, - "types": ["cypress"] - } -} diff --git a/frontend/docs/analytics.md b/frontend/docs/analytics.md deleted file mode 100644 index bcde29bb..00000000 --- a/frontend/docs/analytics.md +++ /dev/null @@ -1,4 +0,0 @@ -# Analytics - -This project does not come with any analytics library. -Should you decide to use one, you may want to consider [Angulartics2](https://github.com/angulartics/angulartics2). diff --git a/frontend/docs/backend-proxy.md b/frontend/docs/backend-proxy.md deleted file mode 100644 index 36765299..00000000 --- a/frontend/docs/backend-proxy.md +++ /dev/null @@ -1,43 +0,0 @@ -# Backend proxy - -Usually when working on a web application you consume data from custom-made APIs. - -To ease development with our development server integrating live reload while keeping your backend API calls working, -we also have setup a backend proxy to redirect API calls to whatever URL and port you want. This allows you: - -- To develop frontend features without the need to run an API backend locally -- To use a local development server without [CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing) issues -- To debug frontend code with data from a remote testing platform directly - -## How to configure - -In the root folder you will find a `proxy.conf.js`, containing the backend proxy configuration. - -The interesting part is there: - -```js -const proxyConfig = [ - { - context: '/api', - pathRewrite: { '^/api': '' }, - target: 'http://api.icndb.com', - changeOrigin: true, - }, -]; -``` - -This is where you can setup one or more proxy rules. - -For the complete set of options, see the `http-proxy-middleware` -[documentation](https://github.com/chimurai/http-proxy-middleware#options). - -### Corporate proxy support - -To allow external API calls redirection through a corporate proxy, you will also find a `setupForCorporateProxy()` -function in the proxy configuration file. By default, this method configures a corporate proxy agent based on the -`HTTP_PROXY` environment variable, see the [corporate proxy documentation](corporate-proxy.md) for more details. - -If you need to, you can further customize this function to fit the network of your working environment. - -If your corporate proxy use a custom SSL certificate, your may need to add the `secure: false` option to your -backend proxy configuration. diff --git a/frontend/docs/coding-guides/angular.md b/frontend/docs/coding-guides/angular.md deleted file mode 100644 index f2d9a30b..00000000 --- a/frontend/docs/coding-guides/angular.md +++ /dev/null @@ -1,202 +0,0 @@ -# Introduction to Angular and modern design patterns - -[Angular](https://angular.io) (aka Angular 2, 4, 5, 6...) is a new framework completely rewritten from the ground up, -replacing the now well-known [AngularJS](https://angularjs.org) framework (aka Angular 1.x). - -More that just a framework, Angular should now be considered as a whole _platform_ which comes with a complete set of -tools, like its own [CLI](https://github.com/angular/angular-cli), [debug utilities](https://augury.angular.io) or -[performance tools](https://github.com/angular/angular/tree/master/packages/benchpress). - -Angular has been around for some time now, but I still get the feeling that it’s not getting the love it deserved, -probably because of other players in the field like React or VueJS. While the simplicity behind these frameworks can -definitely be attractive, they lack in my opinion what is essential when making big, enterprise-grade apps: a solid -frame to lead both experienced developers and beginners in the same direction and a rational convergence of tools, -patterns and documentation. Yes, the Angular learning curve may seems a little steep, but it’s definitely worth it. - -## Getting started - -#### Newcomer - -If you're new to Angular you may feel overwhelmed by the quantity of new concepts to apprehend, so before digging -into this project you may want to start with [this progressive tutorial](https://angular.io/tutorial) that will guide -you step by step into building a complete Angular application. - -#### AngularJS veteran - -If you come from AngularJS and want to dig straight in the new version, you may want to take a look at the -[AngularJS vs 2 quick reference](https://angular.io/guide/ajs-quick-reference). - -#### Cheatsheet - -Until you know the full Angular API by heart, you may want to keep this -[cheatsheet](https://angular.io/guide/cheatsheet) that resumes the syntax and features on a single page at hand. - -## Style guide - -This project follows the standard [Angular style guide](https://angular.io/guide/styleguide). - -More that just coding rules, this style guide also gives advices and best practices for a good application architecture -and is an **essential reading** for starters. Reading deeper, you can even find many explanations for some design -choices of the framework. - -## FAQ - -There is a lot to dig in Angular and some questions frequently bother people. In fact, most of unclear stuff seems to be -related to modules, for example the dreaded -[**"Core vs Shared modules"**](https://angular.io/guide/ngmodule-faq#what-kinds-of-modules-should-i-have-and-how-should-i-use-them) -question. - -The guys at Angular may have noticed that since you can now find -[a nice FAQ on their website](https://angular.io/guide/ngmodule-faq#ngmodule-faqs) answering all the common questions -regarding modules. Don't hesitate to take a look at it, even if you think you are experienced enough with Angular :wink:. - -## Going deeper - -Even though they are not mandatory, Angular was designed for the use of design patterns you may not be accustomed to, -like [reactive programming](#reactive-programming), [unidirectional data flow](#unidirectional-data-flow) and -[centralized state management](#centralized-state-management). - -These concepts are difficult to resume in a few words, and despite being tightly related to each other they concern -specific parts of an application flow, each being quite deep to learn on its own. - -You will essentially find here a list of good starting points to learn more on these subjects. - -#### Reactive programming - -You may not be aware of it, but Angular is now a _reactive system_ by design. -Although you are not forced to use reactive programming patterns, they make the core of the framework and it is -definitely recommended to learn them if you want to leverage the best of Angular. - -Angular uses [RxJS](http://reactivex.io/rxjs/) to implement the _Observable_ pattern. - -> An _Observable_ is a stream of asynchronous events that can be processed with array-like operators. - -##### From promises to observables - -While AngularJS used to rely heavily on [_Promises_](https://docs.angularjs.org/api/ng/service/$q) to handle -asynchronous events, _Observables_ are now used instead in Angular. Even though in specific cases like for HTTP -requests, an _Observable_ can be converted into a _Promise_, it is recommended to embrace the new paradigm as it can a -lot more than _Promises_, with way less code. This transition is also explained in the -[Angular tutorial](https://angular.io/tutorial/toh-pt6#!%23observables). -Once you have made the switch, you will never look back again. - -##### Learning references - -- [What is reactive programming?](http://paulstovell.com/blog/reactive-programming), explained nicely through a simple - imaged story _(5 min)_ - -- [The introduction to reactive programming you've been missing](https://gist.github.com/staltz/868e7e9bc2a7b8c1f754), - the title says it all _(30 min)_ - -- [Functional reactive programming for Angular 2 developers](http://blog.angular-university.io/functional-reactive-programming-for-angular-2-developers-rxjs-and-observables/), - see the functional reactive programming principles in practice with Angular _(15 min)_ - -- [RxMarbles](http://rxmarbles.com), a graphical representation of Rx operators that greatly help to understand their - usage - -#### Unidirectional data flow - -In opposition with AngularJS where one of its selling points was two-way data binding which ended up causing a lot of -major headaches for complex applications, Angular now enforces unidirectional data flow. - -What does it means? Said with other words, it means that change detection cannot cause cycles, which was one of -AngularJS problematic points. It also helps to maintain simpler and more predictable data flows in applications, along -with substantial performance improvements. - -**Wait, then why the Angular documentation have mention of a -[two-way binding syntax](https://angular.io/guide/template-syntax#binding-syntax-an-overview)?** - -If you look closely, the new two-way binding syntax is just syntactic sugar to combine two _one-way_ bindings (a -_property_ and _event_ binding), keeping the data flow unidirectional. - -This change is really important, as it was often the cause of performance issues with AngularJS, and it one of the -pillars enabling better performance in new Angular apps. - -While Angular tries to stay _pattern-agnostic_ and can be used with conventional MV\* patterns, it was designed with -reactive programming in mind and really shines when used with reactive data flow patterns like -[redux](http://redux.js.org/docs/basics/DataFlow.html), -[Flux](https://facebook.github.io/flux/docs/in-depth-overview.html#content) or -[MVI](http://futurice.com/blog/reactive-mvc-and-the-virtual-dom). - -#### Centralized state management - -As applications grow in size, keeping track of the all its individual components state and data flows can become -tedious, and tend to be difficult to manage and debug. - -The main goal of using a centralized state management is to make state changes _predictable_ by imposing certain -restrictions on how and when updates can happen, using _unidirectional data flow_. - -This approach was first made popular with React with introduction of the -[Flux](https://facebook.github.io/flux/docs/in-depth-overview.html#content) architecture. Many libraries emerged then -trying to adapt and refine the original concept, and one of these gained massive popularity by providing a simpler, -elegant alternative: [Redux](http://redux.js.org/docs/basics/DataFlow.html). - -Redux is at the same time a library (with the big _R_) and a design pattern (with the little _r_), the latter being -framework-agnostic and working very well with Angular. - -The _redux_ design pattern is based on these [3 principles](http://redux.js.org/docs/introduction/ThreePrinciples.html): - -- The application state is a _single immutable_ data structure -- A state change is triggered by an _action_, an object describing what happened -- Pure functions called _reducers_ take the previous state and the next action to compute the new state - -The core concepts behind these principles are nicely explained in -[this example](http://redux.js.org/docs/introduction/CoreConcepts.html) _(3 min)_. - -For those interested, the redux pattern was notably inspired by -[The Elm Architecture](https://guide.elm-lang.org/architecture/) and the [CQRS](https://martinfowler.com/bliki/CQRS.html) -pattern. - -##### Which library to use? - -You can make Angular work with any state management library you like, but your best bet would be to use -[NGXS](http://ngxs.io) or [@ngrx](https://github.com/ngrx/platform). Both works the same as the popular -[Redux](http://redux.js.org) library, but with a tight integration with Angular and [RxJS](http://reactivex.io/rxjs/), -with some nice additional developer utilities. - -NGXS is based on the same concepts as @ngrx, but with less boilerplate and a nicer syntax, making it less intimidating. - -Here are some resources to get started: - -- [Angular NGXS tutorial with example from scratch](https://appdividend.com/2018/07/03/angular-ngxs-tutorial-with-example-from-scratch/), - a guided tutorial for NGXS _(10 min)_ - -- [Build a better Angular 2 application with redux and ngrx](http://onehungrymind.com/build-better-angular-2-application-redux-ngrx/), - a nice tutorial for @ngrx _(30 min)_ - -- [Comprehensive introduction to @ngrx/store](https://gist.github.com/btroncone/a6e4347326749f938510), an in-depth - walkthrough to this library usage in Angular _(60 min)_ - -##### When to use it? - -You may have noticed that the starter template does not include a centralized state management system out of the box. -Why is that? Well, while there is many benefits from using this pattern, the choice is ultimately up to your team and -what you want to achieve with your app. - -Keep in mind that using a single centralized state for your app introduces a new layer a complexity -[that might not be needed](https://medium.com/@dan_abramov/you-might-not-need-redux-be46360cf367), depending of your -goal. - -## Optimizing performance - -While the new Angular version resolves by design most of the performance issues that could be experienced with -AngularJS, there is always room for improvements. Just keep in mind that delivering an app with good performance is -often a matter of common sense and sane development practices. - -Here is [a list of key points](https://github.com/mgechev/angular-performance-checklist) to check for in your app to -make sure you deliver the best experience to your customers. - -After going through the checklist, make sure to also run an audit of your page through -[**Lighthouse**](https://developers.google.com/web/tools/lighthouse/), the latest Google tool that gives you meaningful -insight about your app performance, accessibility, mobile compatibility and more. - -## Keeping Angular up-to-date - -Angular development is moving fast, and updates to the core libs and tools are pushed regularly. - -Fortunately, the Angular team provides tools to help you follow through the updates: - -- `npm run ng update` allows you to update your app and its dependencies - -- The [Angular update website](https://update.angular.io) guides you through Angular changes and migrations, providing - step by step guides from one version to another. diff --git a/frontend/docs/coding-guides/build-specific-configurations.md b/frontend/docs/coding-guides/build-specific-configurations.md deleted file mode 100644 index 5182601f..00000000 --- a/frontend/docs/coding-guides/build-specific-configurations.md +++ /dev/null @@ -1,276 +0,0 @@ -# Build-Specific Configuration - -## tl;dr's - -ngx-rocket comes with a very helpful `env` script that will save environment-variables set at build time to constants -that can be used as configuration for your code. When combined with the `dotenv-cli` package, it enables maximum -configurability while maintaining lots of simplicity for local development and testing. - -### Cookbook for maximum independence of deployment-specific configuration - -Disclaimer: If you have a full-stack app in a monorepo, keep separate `.env` files for server-side and client-side -configs, and make sure `.env` files are .gitignore'd and that secrets never make it into client-side `.env` file. - -For each configurable variable (e.g. BROWSER_URL, API_URL): - -- Add it to package.json's env script so that the build-time variables will be saved for runtime: - - ```javascript - { - "scripts": { - "env": "ngx-scripts env npm_package_version BROWSER_URL API_URL", -  } - } - ``` - -- Add it to or edit it in src/environments/environment.ts to expose it to your app as e.g. environment.API_URL: - ```typescript - export const environment = { - // ... - API_URL: env.API_URL, - BROWSER_URL: env.BROWSER_URL, - // ... - }; - ``` -- Configure your CI's deployment to set the variables and export them to the build script before building - if your CI - gives you a shell script to run, make it something like this: - ```shell - # bourne-like shells... - export API_URL='https://api.staging.example.com' - export BROWSER_URL='https://staging.example.com' - # ... - npm run build:ssr-and-client - ``` -- Finally, to have your cake and eat it too and avoid having to do all that for local development and testing (or clutter - your package.json up), install the `dotenv-cli` package and update your development-related npm scripts to take advantage - of it: - ```shell - # environment.development.env.sh - BROWSER_URL='http://localhost:4200' - API_URL='http://localhost:4200' - ``` - ```javascript - { - "scripts": { - "start": "dotenv -e environment.development.env.sh -- npm run env && ng serve --aot", - } - } - ``` - -This way, app configurations will always come from deploy-specific environment variables, and your development environments -are still easy to work with. - -For configuring the build itself (for example, if you want your QA build to be similar to your production build, but with -source maps enabled), consider avoiding adding a build configuration to angular.json, and instead adding the respective -overriding flag to the `ng` command in package.json: - -```javascript -{ - "scripts": { - "build:client-and-server-bundles:qa": "NG_BUILD_OVERRIDES='--sourceMap=true' npm run build:client-and-server-bundles", - "build:client-and-server-bundles": "npm run build:client-bundles && npm run build:server-bundles", - "build:client-bundles": "npm run env && ng build --prod $NG_BUILD_OVERRIDES", - } -} -``` - -The development server API proxy config can read runtime environment variables, so you can avoid having a superficial -dev-server configuration by taking advantage of them: - -```javascript -{ - "scripts": { - "start": "dotenv -e environment.development.env.sh -- npm run env && API_PROXY_HOST='http://localhost:9000' ng serve --aot", - } -} -``` - -```javascript -const proxyConfig = [ - { - context: '/api', - pathRewrite: { '^/api': '' }, - target: `${process.env.API_PROXY_HOST}/api`, - changeOrigin: true, - secure: false, - }, - { - context: '/auth', - pathRewrite: { '^/auth': '' }, - target: `${process.env.API_PROXY_HOST}/auth`, - changeOrigin: true, - secure: false, - }, -]; -``` - -Quick SSR note: SSR works by building all the client bundles like normal, but then rendering them in real-time. So, - -- the rest of your app from `main.server.ts` down has access to your build-time environment only, like your normal - client bundles -- but `server.ts` (the file configuring and running express) has access to your serve-time environment variables - -### Less optimal alternatives - -- On the opposite extreme of the spectrum, you can keep all build-specific configuration in a separate environment - file for each environment using Angular's built-in `fileReplacements`, but then you'll need a separate environment - file even for deployment-specific configuration (like hostnames), which can get out of hand fast. -- For a middle-of-the-road approach, you can divide configuration into two groups: - - Configuration shared by each environment-type: - - Environment-type examples include local development, staging/qa, test, production... - - Examples of configuration like this include: - - In test, animations are always disabled, but for all other environments, they're enabled - - In production, the payment gateway's publishable key is the live key, but all other environments use the - test key - - Configuration that sometimes needs to be specific to an individual deployment of a given environment: - - Examples of configuration like this include: - - This particular staging/qa server's base for constructing URLs is qa-stable.example.com, but qa/staging - environments could also be deployed to preprod.example.com or localhost:8081 or anywhereelse:7000. - - This particular deployment uses a specific bucket for Amazon S3 uploads - - In this approach, you can use Angular's `fileReplacements` for anything environment-specific and ngx-rocket's - `env` for anything deployment-specific. You can even have certain deployment-specific configuration fall back - to environment-specific defaults for certain environments like so: - ```javascript - export const environment = { - // ... - BROWSER_URL: env.BROWSER_URL || 'https://qa.example.com', - // ... - }; - ``` -- If you don't have lots of environment variables, you can avoid dotenv-cli and use your particular shell's method - to expose the variables before running the ngx-rocket env tool. - -## Introduction - -When building any maintainable application, a separation of configuration and code is always desired. In the case -of configuration, some of it will need to vary from environment to environment, build to build, or deployment to -deployment. - -This guide focuses on this type of build-specific configuration in a very broad sense of an Angular app, describing -the specific Angular ways of controlling these configurations, detailing some angular-specific challenges, and -highlighting some ngx-rocket tooling that help with them in mind. - -For an even broader non-Angular introduction of these concepts, see the -[The Twelve-Factor App](https://12factor.net/config) methodology's opinions on how this type of configuration -should be managed. - -## Types of configuration - -At the highest level, build-specific configuration can be divided into two categories: - -1. Configuration for how your app is built and served -2. Configuration used by your codebase - -### Configuration for how your app is built and served - -This type of build-specific configuration is not used by your code, but is used to control the build system itself. -Configuration like this goes into Angular's -[workspace configuration](https://angular.io/guide/workspace-config#alternate-build-configurations). Instead of -rehashing existing documentation on this, this document will highlight how it relates to this subject. Namely, the -fact that in addition to specifying _HOW_ the app is built for each build configuration, the workspace configuration -allows mapping each build configuration to a separate environment configuration file for your codebase as well. It -also allows for making separate dev-server configurations in case you need to run it differently. - -Therefore, each build configuration in the workspace configuration file is a tuple of -(how-to-build, environment-file-for-codebase), and you'll need a separate configuration for each combination. - -## Angular's out-of-the-box environment configuration - -### When it works well - -This setup works quite well for configuration that's shared among all instances of an environment, like the following -examples: - -- **test** environment always builds without source maps, disables animations, uses a recaptcha test key, and disables - analytics -- **dev** environment always builds with source maps, enables animations, uses a recaptcha live key, and disables - analytics -- **qa** environment always builds with source maps, enables animations, uses a recaptcha live key, and disables - analytics -- **prod** environment always builds without source maps, enables animations, uses a recaptcha live key, and enables - analytics - -### Limitations of Angular's `fileReplacements` - -But for certain deployment-specific configuration, things start to get really hairy, like in these examples: - -- QA build configuration needs to be built for local deployment, deployment to a server on the internet for QA - purposes, and also deployment to another server on the internet for staging purposes -- Production build needs multiple different deployments of the same app to different servers - -These cases can cause problems when: - -- Each deployment needs a separate API URL -- Each deployment needs a separate URL for building its own URLs to where it's deployed -- Each deployment needs separate API keys, bucket names, etc - -You _COULD_ start creating separate configurations for each deployment, each with its own `fileReplacements`, but that -would be really messy. - -### Workarounds that don't work well - -One workaround would be to keep such configurations as globals in a separate deployment-specific script file. But -that's pretty messy too. More importantly, there are limitations to where they can be used. For example, because -of AOT, such configuration variables cannot be used in Angular's decorators, because they're not statically -analyzable (i.e. their values knowable at build-time). So it would be better if we can keep everything in the same place. - -### ngx-rocket to the rescue - -The ngx-rocket `env` task solves this problem really well, and avoids the need for separate `environment.ts` files for -deployment-specific configuration. - -To add a deployment-specific configuration: - -1. edit the existing `environment.ts` files for whichever environments you'd like to make that variable - deployment-specific for by having it come from the imported "env" object - pro tip: you can even make it fall - back to an environment-based default and still be statically analyzable! -2. add that variable name to the npm script's `env` task - -Now, as long as you have that environment variable set in the shell running the build, the `env` task will save it into -the `.env.ts` file before building. - -If you really want, you can take things even further to the twelve-factor extreme, and you can even eliminate the -need for `fileReplacements` entirely, and make all configuration come from environment variables. Whether this will be -the right approach for your project will be up to you. - -This makes separate deployments awesome and flexible, but unfortunately makes things a little bit of a hassle for your -local development, test, etc. environments because you have the burden of providing all those keys, settings, etc. as -environment variables. - -To avoid having to do that, you'll can create a .gitignore'd `.env` file with all the variables set, and source it -with your shell (e.g. `source .env.sh && npm env` in bourne-like shells or `env.bat; npm env` in windows). - -```shell -# bourne-like .env.sh -export BROWSER_URL=localhost:4200 -``` - -```shell -REM windows env.bat -SET BROWSER_URL=localhost:4200 -``` - -Luckily for us, there's a package called `dotenv-cli` that uses the `dotenv` package and does this in a cleaner and -cross-platform way and comes with even more bells and whistles. You should use that instead, and make your env file -like this instead: - -```shell -BROWSER_URL=localhost:4200 -``` - -## When you can use environment variables directly without ngx-rocket `env` - -As a sidenote, ngx-rocket `env` isn't used for the proxy config file, because it isn't built and ran separately. -Fortunately, for that same reason, you can directly use `process.env` within the proxy config file to avoid having -separate proxy configs in most cases. - -On that same note, the `server.ts` for SSR builds can also access `process.env` as it's set at runtime. But keep in mind -that it stops there - the app itself is built, so even in SSR the client app can't access process environment variables. - -## Security Considerations - -Never forget that your entire Angular app goes to the client, including its configuration, including the environment -variables you pass to the env task! As usual, you should **never add sensitive keys or secrets to the env task**. - -Finally, if your Angular project is the client-side of a full-stack monorepo, make sure to keep the client-side `.env` -file separate from the server-side `.env` file, since your server-side is bound to have secrets. diff --git a/frontend/docs/coding-guides/e2e-tests.md b/frontend/docs/coding-guides/e2e-tests.md deleted file mode 100644 index cf17d237..00000000 --- a/frontend/docs/coding-guides/e2e-tests.md +++ /dev/null @@ -1,97 +0,0 @@ -# End-to-end tests coding guide - -End-to-end (E2E for short) tests are meant to test the behavior of your application, from start to finish. - -While unit tests are the first choice for catching bugs and regression on individual components, it is a good idea to -complement them with test cases covering the integration between the individual components, hence the need for E2E -tests. - -These tests use [Cypress](https://www.cypress.io/), which is a next generation front end testing tool built for the modern web. - -If you are new to Cypress, you can read the [introduction guide](https://docs.cypress.io/guides/core-concepts/introduction-to-cypress#Cypress-Can-Be-Simple-Sometimes), as although it seems similar on the surface as other tools like Selenium or Protractor, Cypress is fundamentally different. - -## Good practices - -- Avoid whenever possible inter-dependencies between your E2E tests -- Run E2E tests on your continuous integration server against different browsers -- If you use an Agile methodology, cover each user story acceptance factors with an E2E test - -## Page objects - -E2E tests should follow the _[Page Object](https://github.com/SeleniumHQ/selenium/wiki/PageObjects)_ pattern. - -#### What is a page object? - -A page object: - -- Models the objects on a page under test: - - _Properties_ wrap page elements - - _Methods_ wrap code that interacts with the page elements -- Simplifies the test scripts -- Reduces the amount of duplicated code - -If the UI changes, the fix only needs to be applied in one place. - -#### How to define a page object - -```typescript -// login.po.ts -export class LoginPage { - get emailInput() { - return cy.get('input[name=^"email"]'); - } - - get passwordInput() { - return cy.get('input[name=^"password"]'); - } - - get loginButton() { - return cy.get('button[(click)^="login"]'); - } - - get registerButton() { - return cy.get('button[(click)^="register"]'); - } - - get greeting() { - return cy.get('.greeting'); - } - - visit() { - cy.visit('/'); - } -} -``` - -#### How to use a page object - -```typescript -// login.e2e-spec.ts -import { LoginPage } from './login.po'; - -describe('Login', () => { - let page: LoginPage; - - beforeEach(async () => { - page = new LoginPage(); - page.visit(); - }); - - it('should navigate to the register page when the register button is clicked', () => { - page.registerButton.click(); - cy.url().should('include', '/register'); - }); - - it('should allow a user to log in', async () => { - page.emailInput.type('test@mail.com'); - page.passwordInput.type('abc123'); - page.loginButton.click(); - page.greeting.contains('Welcome, Test User'); - }); -}); -``` - -## Credits - -Parts of this guide were freely inspired by this -[presentation](https://docs.google.com/presentation/d/1B6manhG0zEXkC-H-tPo2vwU06JhL8w9-XCF9oehXzAQ). diff --git a/frontend/docs/coding-guides/html.md b/frontend/docs/coding-guides/html.md deleted file mode 100644 index e2ec7101..00000000 --- a/frontend/docs/coding-guides/html.md +++ /dev/null @@ -1,39 +0,0 @@ -# HTML coding guide - -## Naming conventions - -- Everything should be named in `kebab-case` (lowercase words separated with a `-`): tags, attributes, IDs, etc, - **except for everything bound to Angular** such variables, directives or events which should be in `camelCase` -- File names should always be in `kebab-case` - -## Coding rules - -- Use HTML5 doctype: `` -- Use HTML [semantic elements](https://developer.mozilla.org/docs/Web/HTML/Sections_and_Outlines_of_an_HTML5_document) -- Use double quotes `"` around attribute values in tags -- Use a new line for every block, list, or table element, and indent every such child element -- Clearly Separate structure (HTML) from presentation (CSS) from behavior (JavaScript): - - Never use inline CSS or JavaScript - - Keep any logic out of the HTML -- `type` attribute for stylesheets and script tags should be omitted - -## Common pitfalls - -- **Block**-type tags cannot be nested inside **inline**-type tags: a `
` tag cannot be nested in a ``. - This rule also applies regarding the `display` value of an element. -- HTML is **not** XML: empty tags cannot be self-closing and will result in improper results - - `
` will be interpreted as a simple `
` without closing tag! - - The only tags that allows self-closing are the one that does not require a closing tag in first place: - these are the void elements that do not not accept content `
`, `
`, ``, ``, ``, `` - (and others). - -## Templates - -In accordance with the [Angular style guide](https://angular.io/guide/styleguide), HTML templates should be extracted in -separate files, when more than 3 lines. - -Only use inline templates sparingly in very simple components with less than 3 lines of HTML. - -## Enforcement - -Coding rules enforcement and basic sanity checks are done in this project by [HTMLHint](http://htmlhint.com). diff --git a/frontend/docs/coding-guides/sass.md b/frontend/docs/coding-guides/sass.md deleted file mode 100644 index b21f38b7..00000000 --- a/frontend/docs/coding-guides/sass.md +++ /dev/null @@ -1,102 +0,0 @@ -# Sass coding guide - -[Sass](http://sass-lang.com) is a superset of CSS, which brings a lot of developer candy to help scaling CSS in large -projects and keeping it maintainable. - -The main benefits of using Sass over plain CSS are _variables_, _nesting_ and _mixins_, see the -[basics guide](http://sass-lang.com/guide) for more details. - -> Note that this project use the newer, CSS-compatible **SCSS** syntax over the old -> [indented syntax](http://sass-lang.com/documentation/file.INDENTED_SYNTAX.html). - -## Naming conventions - -- In the CSS world, everything should be named in `kebab-case` (lowercase words separated with a `-`). -- File names should always be in `kebab-case` - -## Coding rules - -- Use single quotes `'` for strings -- Use this general nesting hierarchy when constructing your styles: - - ```scss - // The base component class acts as the namespace, to avoid naming and style collisions - .my-component { - // Put here all component elements (flat) - .my-element { - // Use a third-level only for modifiers and state variations - &.active { ... } - } - } - ``` - - Note that with - [Angular view encapsulation](https://angular.io/docs/ts/latest/guide/component-styles.html#!#view-encapsulation), - the first "namespace" level of nesting is not necessary as Angular takes care of the scoping for avoid collisions. - - > As a side note, we are aware of the [BEM naming approach](https://en.bem.info/tools/bem/bem-naming/), but we found - > it impractical for large projects. The nesting approach has drawbacks such as increased specificity, but it helps - > keeping everything nicely organized, and more importantly, _scoped_. - -Also keep in mind this general rules: - -- Always use **class selectors**, never use ID selectors and avoid element selectors whenever possible -- No more than **3 levels** of nesting -- No more than **3 qualifiers** - -## Best practices - -- Use object-oriented CSS (OOCSS): - - - Factorize common code in base class, and extend it, for example: - - ```scss - // Base button class - .btn { ... } - - // Color variation - .btn-warning { ... } - - // Size variation - .btn-small { ... } - ``` - - - Try to name class by semantic, not style nor function for better reusability: - Use `.btn-warning`, not `btn-orange` nor `btn-cancel` - - Avoid undoing style, refactor using common base classes and extensions - -- Keep your style scoped - - - Clearly separate **global** (think _framework_) and **components** style - - Global style should only go in `src/theme/`, never in components - - Avoid style interactions between components, if some style may need to be shared, refactor it as a framework - component in put it in your global theme. - - Avoid using wider selectors than needed: always use classes if you can! - -- Avoid rules multiplication - - - The less CSS the better, factorize rules whenever it's possible - - CSS is code, and like any code frequent refactoring is healthy - -- When ugly hacks cannot be avoided, create an explicit `src/hacks.scss` file and put it in: - - These ugly hacks should only be **temporary** - - Each hack should be documented with the author name, the problem and hack reason - - Limit this file to a reasonable length (~100 lines) and refactor hacks with proper solutions when the limit is - reached. - -## Pitfalls - -- Never use the `!important` keyword. Ever. -- Never use **inline** style in html, even _just for debugging_ (because we **KNOW** it will end up in your commit) - -## Browser compatibility - -You should never use browser-specific prefixes in your code, as [autoprefixer](https://github.com/postcss/autoprefixer) -takes care of that part for you during the build process. -You just need to declare which browsers you target in the [`browserslist`](https://github.com/ai/browserslist) file. - -## Enforcement - -Coding rules are enforced in this project with [stylelint](https://stylelint.io). -This tool also checks the compatibility of the rules used against the browsers you are targeting (specified in the -[`browserslist`](https://github.com/ai/browserslist) file), via [doiuse](https://github.com/anandthakker/doiuse). diff --git a/frontend/docs/coding-guides/typescript.md b/frontend/docs/coding-guides/typescript.md deleted file mode 100644 index a2069bc5..00000000 --- a/frontend/docs/coding-guides/typescript.md +++ /dev/null @@ -1,63 +0,0 @@ -# TypeScript coding guide - -[TypeScript](http://www.typescriptlang.org) is a superset of JavaScript that greatly helps building large web -applications. - -Coding conventions and best practices comes from the -[TypeScript guidelines](https://github.com/Microsoft/TypeScript/wiki/Coding-guidelines), and are also detailed in the -[TypeScript Deep Dive Style Guide](https://basarat.gitbooks.io/typescript/content/docs/styleguide/styleguide.html). -In addition, this project also follows the general [Angular style guide](https://angular.io/guide/styleguide). - -## Naming conventions - -- Use `PascalCase` for types, classes, interfaces, constants and enum values. -- Use `camelCase` for variables, properties and functions -- Avoid prefixing interfaces with a capital `I`, see [Angular style guide](https://angular.io/guide/styleguide#!#03-03) -- Do not use `_` as a prefix for private properties. An exception can be made for backing fields like this: - ```typescript - private _foo: string; - get foo() { return this._foo; } // foo is read-only to consumers - ``` - -## Ordering - -- Within a file, type definitions should come first -- Within a class, these priorities should be respected: - - Properties comes before functions - - Static symbols comes before instance symbols - - Public symbols comes before private symbols - -## Coding rules - -- Use single quotes `'` for strings -- Always use strict equality checks: `===` and `!==` instead of `==` or `!=` to avoid comparison pitfalls (see - [JavaScript equality table](https://dorey.github.io/JavaScript-Equality-Table/)). - The only accepted usage for `==` is when you want to check a value against `null` or `undefined`. -- Use `[]` instead of `Array` constructor -- Use `{}` instead of `Object` constructor -- Always specify types for function parameters and returns (if applicable) -- Do not export types/functions unless you need to share it across multiple components -- Do not introduce new types/values to the global namespace -- Use arrow functions over anonymous function expressions -- Only surround arrow function parameters when necessary. - For example, `(x) => x + x` is wrong but the following are correct: - - `x => x + x` - - `(x, y) => x + y` - - `(x: T, y: T) => x === y` - -## Definitions - -In order to infer types from JavaScript modules, TypeScript language supports external type definitions. They are -located in the `node_modules/@types` folder. - -To manage type definitions, use standard `npm install|update|remove` commands. - -## Enforcement - -Coding rules are enforced in this project via [TSLint](https://github.com/palantir/tslint). -Angular-specific rules are also enforced via the [Codelyzer](https://github.com/mgechev/codelyzer) rule extensions. - -## Learn more - -The read of [TypeScript Deep Dive](https://basarat.gitbooks.io/typescript) is recommended, this is a very good -reference book for TypeScript (and also open-source). diff --git a/frontend/docs/coding-guides/unit-tests.md b/frontend/docs/coding-guides/unit-tests.md deleted file mode 100644 index 756e0bcb..00000000 --- a/frontend/docs/coding-guides/unit-tests.md +++ /dev/null @@ -1,46 +0,0 @@ -# Unit tests coding guide - -The main objective of unit tests is to detect regressions and to help you design software components. A suite of -_good_ unit tests can be _immensely_ valuable for your project and makes it easier to refactor and expand your code. -But keep in mind that a suite of _bad_ unit tests can also be _immensely_ painful, and hurt your development by -inhibiting your ability to refactor or alter your code in any way. - -## What to test? - -Everything! But if you need priorities, at least all business logic code must be tested: services, helpers, models... -Shared directives/components should also be covered by unit tests, if you do not have the time to test every single -component. - -Keep in mind that component unit tests should not overlap with [end-to-end tests](e2e-tests.md): while unit the tests -cover the isolated behavior of the component bindings and methods, the end-to-end tests in opposition should cover the -integration and interactions with other app components based on real use cases scenarios. - -## Good practices - -- Name your tests cleanly and consistently -- Do not only test nominal cases, the most important tests are the one covering the edge cases -- Each test should be independent to all the others -- Avoid unnecessary assertions: it's counter-productive to assert anything covered by another test, it just increase - pointless failures and maintenance workload -- Test only one code unit at a time: if you cannot do this, it means you have an architecture problem in your app -- Mock out all external dependencies and state: if there is too much to mock, it is often a sign that maybe you - should split your tested module into several more independent modules -- Clearly separate or identify these 3 stages of each unit test (the _3A_): _arrange_, _act_ and _assert_ -- When you fix a bug, add a test case for it to prevent regression - -## Pitfalls - -- Sometimes your architecture might mean your code modify static variables during unit tests. Avoid this if you can, - but if you can't, at least make sure each test resets the relevant statics before and after your tests. -- Don’t unit-test configuration settings -- Improving test coverage is good, but having meaningful tests is better: start with the latter first, and **only after - essential features of your code unit are tested**, your can think of improving the coverage. - -## Unit testing with Angular - -A good starting point for learning is the official -[testing guide](https://angular.io/docs/ts/latest/guide/testing.html). - -But as you will most likely want to go bit further in real world apps, these -[example test snippets](https://gist.github.com/wkwiatek/e8a4a9d92abc4739f04f5abddd3de8a7) are also very helpful to -learn how to cover most common testing use cases. diff --git a/frontend/docs/corporate-proxy.md b/frontend/docs/corporate-proxy.md deleted file mode 100644 index 556cb130..00000000 --- a/frontend/docs/corporate-proxy.md +++ /dev/null @@ -1,51 +0,0 @@ -# Working behind a corporate proxy - -## Environment - -Most tools (including npm and git) use the `HTTP_PROXY` and `HTTPS_PROXY` environment variables to work with a -corporate proxy. - -### Windows - -In Windows environments, add the `HTTP_PROXY` and `HTTPS_PROXY` system environment variable, with these values: - -- HTTP_PROXY: `http://:@:` -- HTTPS_PROXY: `%HTTP_PROXY%` - -### Unix - -Add these lines to your `~/.bash_profile` or `~/.profile`: - -```sh -export HTTP_PROXY="http://:@:" -export HTTPS_PROXY="$HTTP_PROXY" -``` - -## Proxy with SSL custom certificate - -Some proxy like **zscaler** use a custom SSL certificate to inspect request, which may cause npm commands to fail. - -To solve this problem, you can disable the `strict-ssl` option in npm. - -## Proxy exceptions - -If you need to access repositories on your local network that should bypass proxy, set the `NO_PROXY` environment -variable, in the same way as `HTTP_PROXY`: - -### Windows - -- NO_PROXY: `127.0.0.1, localhost, ` - -### Unix - -```sh -export NO_PROXY="127.0.0.1, localhost, " -``` - -### Npm - -Run this command in your project directory: - -```sh -npm set strict-ssl false -``` diff --git a/frontend/docs/i18n.md b/frontend/docs/i18n.md deleted file mode 100644 index 13fbc90d..00000000 --- a/frontend/docs/i18n.md +++ /dev/null @@ -1,58 +0,0 @@ -# I18n - -The internationalization of the application is managed by [ngx-translate](https://github.com/ngx-translate/core). - -## Adding translatable strings - -### In HTML templates - -Use the `translate` directive on an HTML element to automatically translate its content: - -```html -This text will be translated. -``` - -You can also use the `translate` pipe if needed: - -```html - -``` - -### In TypeScript code - -If you need to translate strings in JavaScript code, import the `TranslateService` dependency and use the asynchronous -`get()` method: - -```typescript -let title; -translateService.get('My page title').subscribe((res: string) => { - title = res; -}); -``` - -## Extracting strings to translate - -Once you are ready to translate your app, just run `npm run translations:extract`. -It will create a `template.json` file in the `src/translations` folder. - -You can then use any text or code editor to generate the `.json` files for each of your supported languages, and put -them in the `src/translations` folder. - -Do no forget to edit the files in `src/environment` to add the supported languages of your application. - -### Marking strings for extraction - -If strings are not directly passed to `translateService` or put in HTML templates, they may be missing from the -extraction process. - -For these cases, you have to use the dummy `marker()` function: - -```typescript -import { marker } from '@biesbjerg/ngx-translate-extract-marker'; - -function toBeTranslatedLater() { - return marker('A string to be translated'); -} -``` - -Strings marked like this will then be properly extracted. diff --git a/frontend/docs/readme.md b/frontend/docs/readme.md deleted file mode 100644 index 23532818..00000000 --- a/frontend/docs/readme.md +++ /dev/null @@ -1,9 +0,0 @@ -# sophia-ng - -Welcome to the project documentation! - -Use `npm run docs` for easier navigation. - -## Available documentation - -[[index]] diff --git a/frontend/docs/routing.md b/frontend/docs/routing.md deleted file mode 100644 index 704b939a..00000000 --- a/frontend/docs/routing.md +++ /dev/null @@ -1,43 +0,0 @@ -# Browser routing - -To allow navigation without triggering a server request, Angular now use by default the -[HTML5 pushState](https://developer.mozilla.org/en-US/docs/Web/API/History_API#Adding_and_modifying_history_entries) -API enabling natural URL style (like `localhost:4200/home/`), in opposition to Angular 1 which used the _hashbang_ hack -routing style (like `localhost:4200/#/home/`). - -This change has several consequences you should know of, be sure to read the -[browser URL styles](https://angular.io/docs/ts/latest/guide/router.html#!#browser-url-styles) notice to fully -understand the differences between the two approaches. - -In short: - -- It is only supported on modern browsers (IE10+), a [polyfill](https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills#html5-history-api-pushstate-replacestate-popstate) - is required for older browsers. - -- You have the option to perform _server-side rendering_ later if you need to increase your app perceived performance. - -- You need to [configure URL rewriting](#server-configuration) on your server so that all routes serve your index file. - -It is still possible to revert to the hash strategy, but unless you have specific needs, you should stick with the -default HTML5 routing mode. - -## Server configuration - -To allow your angular application working properly as a _Single Page Application_ (SPA) and allow bookmarking or -refreshing any page, you need some configuration on your server, otherwise you will be running into troubles. - -> Note that during development, the live reload server already supports SPA mode. - -The basic idea is simply to serve the `index.html` file for every request aimed at your application. - -Here is an example on how to perform this on an [Express](http://expressjs.com) NodeJS server: - -```js -// Put this in your `server.js` file, after your other rules (APIs, static files...) -app.get('/*', function (req, res) { - res.sendFile(__dirname + '/index.html'); -}); -``` - -For other servers like [Nginx](https://www.nginx.com/blog/creating-nginx-rewrite-rules/) or -[Apache](http://httpd.apache.org/docs/2.0/misc/rewriteguide.html), you may look for how to perform _URL rewriting_. diff --git a/frontend/docs/updating.md b/frontend/docs/updating.md deleted file mode 100644 index 7db7652e..00000000 --- a/frontend/docs/updating.md +++ /dev/null @@ -1,46 +0,0 @@ -# Updating npm dependencies - -- Check outdated packages - -```sh -npm outdated -``` - -- Update local packages according to `package.json` - -```sh -npm update -``` - -- Upgrade packages manually - -```sh -npm install --save[-dev] @latest -``` - -Alternatively, you can use [npm-check](https://github.com/dylang/npm-check) to perform an interactive upgrade: - -```sh -npm-check -u --skip-unused -``` - -## Locking package versions - -Starting from `npm@5` a new `package-lock.json` file is -[automatically generated](https://docs.npmjs.com/files/package-locks) when using `npm install` commands, to ensure a -reproducible dependency tree and avoid unwanted package updates. - -If you use a previous npm version, it is recommended to use [npm shrinkwrap](https://docs.npmjs.com/cli/shrinkwrap) to -lock down all your dependencies version: - -```sh -npm shrinkwrap --dev -``` - -This will create a file `npm-shrinkwrap.json` alongside your `package.json` files. - -> Do not forget to run shrinkwrap each time you manually update your dependencies! - -# Updating angular-related dependencies - -See the [Angular update website](https://update.angular.io) to guide you through the updating/upgrading steps. diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js new file mode 100644 index 00000000..99a007a6 --- /dev/null +++ b/frontend/eslint.config.js @@ -0,0 +1,43 @@ +// @ts-check +const eslint = require("@eslint/js"); +const tseslint = require("typescript-eslint"); +const angular = require("angular-eslint"); + +module.exports = tseslint.config( + { + files: ["**/*.ts"], + extends: [ + eslint.configs.recommended, + ...tseslint.configs.recommended, + ...tseslint.configs.stylistic, + ...angular.configs.tsRecommended, + ], + processor: angular.processInlineTemplates, + rules: { + "@angular-eslint/directive-selector": [ + "error", + { + type: "attribute", + prefix: "app", + style: "camelCase", + }, + ], + "@angular-eslint/component-selector": [ + "error", + { + type: "element", + prefix: "app", + style: "kebab-case", + }, + ], + }, + }, + { + files: ["**/*.html"], + extends: [ + ...angular.configs.templateRecommended, + ...angular.configs.templateAccessibility, + ], + rules: {}, + } +); diff --git a/frontend/jest.config.js b/frontend/jest.config.js deleted file mode 100644 index 02bd4ca3..00000000 --- a/frontend/jest.config.js +++ /dev/null @@ -1,22 +0,0 @@ -const { pathsToModuleNameMapper } = require('ts-jest'); -// In the following statement, replace `./tsconfig` with the path to your `tsconfig` file -// which contains the path mapping (ie the `compilerOptions.paths` option): -const { compilerOptions } = require('./tsconfig.json'); - -module.exports = { - preset: 'jest-preset-angular', - roots: ['src'], - coverageDirectory: 'reports', - setupFilesAfterEnv: ['/src/setup-jest.ts'], - moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { prefix: '/' }), - globals: { - 'ts-jest': { - allowSyntheticDefaultImports: true, - tsconfig: '/tsconfig.spec.json', - diagnostics: { - ignoreCodes: ['TS151001'], - }, - }, - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], -}; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 721b0689..6c62a45a 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,242 +1,228 @@ { - "name": "sophia-ng", - "version": "1.0.0", + "name": "fuse-angular", + "version": "20.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "sophia-ng", - "version": "1.0.0", - "hasInstallScript": true, - "dependencies": { - "@angular/animations": "~14.1.3", - "@angular/cdk": "~14.1.3", - "@angular/common": "~14.1.3", - "@angular/compiler": "~14.1.3", - "@angular/core": "~14.1.3", - "@angular/flex-layout": "^14.0.0-beta.40", - "@angular/forms": "~14.1.3", - "@angular/localize": "~14.1.3", - "@angular/material": "~14.1.3", - "@angular/platform-browser": "~14.1.3", - "@angular/platform-browser-dynamic": "~14.1.3", - "@angular/router": "~14.1.3", - "@fastify/static": "^7.0.4", - "@ngx-translate/core": "^14.0.0", - "date-fns": "^2.29.2", - "lodash": "^4.17.20", - "marked": "^12.0.2", - "material-design-icons-iconfont": "^6.1.0", - "ngx-markdown": "^14.0.1", - "rxjs": "^7.5.0", - "tslib": "^2.3.0", - "zone.js": "~0.11.4" + "name": "fuse-angular", + "version": "20.0.0", + "license": "https://themeforest.net/licenses/standard", + "dependencies": { + "@angular/animations": "18.0.1", + "@angular/cdk": "18.0.1", + "@angular/common": "18.0.1", + "@angular/compiler": "18.0.1", + "@angular/core": "18.0.1", + "@angular/forms": "18.0.1", + "@angular/material": "18.0.1", + "@angular/material-luxon-adapter": "18.0.1", + "@angular/platform-browser": "18.0.1", + "@angular/platform-browser-dynamic": "18.0.1", + "@angular/router": "18.0.1", + "@ngneat/transloco": "6.0.4", + "apexcharts": "3.54.1", + "crypto-js": "4.2.0", + "highlight.js": "11.9.0", + "lodash-es": "4.17.21", + "luxon": "3.4.4", + "ng-apexcharts": "1.11.0", + "ngx-markdown": "^18.1.0", + "ngx-quill": "26.0.1", + "perfect-scrollbar": "1.5.5", + "quill": "2.0.2", + "rxjs": "7.8.1", + "tslib": "2.6.2", + "zone.js": "0.14.6" }, "devDependencies": { - "@angular-builders/jest": "^14.0.1", - "@angular-devkit/build-angular": "~14.1.3", - "@angular-eslint/builder": "~14.0.3", - "@angular-eslint/eslint-plugin": "~14.0.3", - "@angular-eslint/eslint-plugin-template": "~14.0.3", - "@angular-eslint/schematics": "~14.0.3", - "@angular-eslint/template-parser": "~14.0.3", - "@angular/cli": "~14.1.3", - "@angular/compiler-cli": "~14.1.3", - "@angular/language-service": "~14.1.3", - "@biesbjerg/ngx-translate-extract": "^7.0.3", - "@biesbjerg/ngx-translate-extract-marker": "^1.0.0", - "@cypress/schematic": "^2.0.3", - "@ngneat/until-destroy": "^9.0.0", - "@ngx-rocket/scripts": "^5.2.2", - "@types/jest": "^28.1.8", - "@types/lodash": "^4.14.184", - "@types/node": "^14.18.26", - "@typescript-eslint/eslint-plugin": "~5.34.0", - "@typescript-eslint/parser": "~5.34.0", - "cypress": "~10.6.0", - "dotenv-cli": "^7.4.2", - "eslint": "^8.3.0", - "eslint-plugin-import": "2.29.1", - "eslint-plugin-jsdoc": "48.7.0", - "eslint-plugin-prefer-arrow": "1.2.3", - "hads": "^3.0.0", - "https-proxy-agent": "^5.0.0", - "husky": "^8.0.1", - "jest": "^28.1.3", - "postcss": "^8.4.5", - "prettier": "^2.2.1", - "pretty-quick": "^3.1.0", - "pyodide": "^0.26.1", - "stylelint": "~14.11.0", - "stylelint-config-prettier": "^9.0.3", - "stylelint-config-recommended-scss": "~7.0.0", - "stylelint-config-standard": "~28.0.0", - "ts-jest": "^28.0.8", - "ts-node": "^10.1.0", - "typescript": "~4.7.4" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dependencies": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, + "@angular-devkit/build-angular": "18.0.2", + "@angular/cli": "18.0.2", + "@angular/compiler-cli": "18.0.1", + "@tailwindcss/typography": "0.5.13", + "@types/chroma-js": "2.4.4", + "@types/crypto-js": "4.2.2", + "@types/highlight.js": "10.1.0", + "@types/jasmine": "5.1.4", + "@types/lodash": "4.17.4", + "@types/lodash-es": "4.17.12", + "@types/luxon": "3.4.2", + "angular-eslint": "18.3.1", + "autoprefixer": "10.4.19", + "chroma-js": "2.4.2", + "eslint": "^9.9.1", + "jasmine-core": "5.1.2", + "karma": "6.4.3", + "karma-chrome-launcher": "3.2.0", + "karma-coverage": "2.2.1", + "karma-jasmine": "5.1.0", + "karma-jasmine-html-reporter": "2.1.0", + "lodash": "4.17.21", + "postcss": "8.4.38", + "prettier": "3.3.0", + "prettier-plugin-organize-imports": "3.2.4", + "prettier-plugin-tailwindcss": "0.6.1", + "tailwindcss": "3.4.3", + "typescript": "5.4.5", + "typescript-eslint": "8.2.0" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, "engines": { - "node": ">=6.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@angular-builders/jest": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/@angular-builders/jest/-/jest-14.1.0.tgz", - "integrity": "sha512-uGXyJ40F7HXfoWwW1EK5U75sUUQ4zVireLYPUYWT1/t1vqizss0mIPR026bMWwScWJhetdopxlWcql4wfNuXyQ==", + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, "dependencies": { - "@angular-devkit/architect": ">=0.1400.0 < 0.1500.0", - "@angular-devkit/core": "^14.0.0", - "jest-preset-angular": "12.2.2", - "lodash": "^4.17.15" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { - "node": "^14.15.0 || >=16.10.0" - }, - "peerDependencies": { - "@angular-devkit/build-angular": "^14.0.0", - "@angular/compiler-cli": "^14.0.0", - "@angular/core": "^14.0.0", - "@angular/platform-browser-dynamic": "^14.0.0", - "jest": ">=28" + "node": ">=6.0.0" } }, "node_modules/@angular-devkit/architect": { - "version": "0.1402.13", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1402.13.tgz", - "integrity": "sha512-n0ISBuvkZHoOpAzuAZql1TU9VLHUE9e/a9g4VNOPHewjMzpN02VqeGKvJfOCKtzkCs6gVssIlILm2/SXxkIFxQ==", + "version": "0.1800.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1800.2.tgz", + "integrity": "sha512-PX7lCTAqWe9C40+fie+DAc8vhpGA+JgZKWWrMHUTV/iZx8RXx2X4xGQsqYu36p4i3MSfQdbn+0xLWGmjScPVOQ==", "dev": true, "dependencies": { - "@angular-devkit/core": "14.2.13", - "rxjs": "6.6.7" + "@angular-devkit/core": "18.0.2", + "rxjs": "7.8.1" }, "engines": { - "node": "^14.15.0 || >=16.10.0", + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" } }, - "node_modules/@angular-devkit/architect/node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/@angular-devkit/architect/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, "node_modules/@angular-devkit/build-angular": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-14.1.3.tgz", - "integrity": "sha512-LZCGd68LCVOwgcGC9DVfjc+wmsTbQmrTMIjWPMXkqufmicEFptR7ocr2dBFJRiVPwqRj+/J+A98cck0GYRC5fw==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "2.2.0", - "@angular-devkit/architect": "0.1401.3", - "@angular-devkit/build-webpack": "0.1401.3", - "@angular-devkit/core": "14.1.3", - "@babel/core": "7.18.6", - "@babel/generator": "7.18.7", - "@babel/helper-annotate-as-pure": "7.18.6", - "@babel/plugin-proposal-async-generator-functions": "7.18.6", - "@babel/plugin-transform-async-to-generator": "7.18.6", - "@babel/plugin-transform-runtime": "7.18.6", - "@babel/preset-env": "7.18.6", - "@babel/runtime": "7.18.6", - "@babel/template": "7.18.6", + "version": "18.0.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.0.2.tgz", + "integrity": "sha512-cQkTx7XaIPj6+DXo6wZmO4iY0hOOfPDnSN/+m84XpBW0tuPGxH7Z9B6wV+Uwcpm9HGPqzRA7VZyPsqbK860b0Q==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "2.3.0", + "@angular-devkit/architect": "0.1800.2", + "@angular-devkit/build-webpack": "0.1800.2", + "@angular-devkit/core": "18.0.2", + "@angular/build": "18.0.2", + "@babel/core": "7.24.5", + "@babel/generator": "7.24.5", + "@babel/helper-annotate-as-pure": "7.22.5", + "@babel/helper-split-export-declaration": "7.24.5", + "@babel/plugin-transform-async-generator-functions": "7.24.3", + "@babel/plugin-transform-async-to-generator": "7.24.1", + "@babel/plugin-transform-runtime": "7.24.3", + "@babel/preset-env": "7.24.5", + "@babel/runtime": "7.24.5", "@discoveryjs/json-ext": "0.5.7", - "@ngtools/webpack": "14.1.3", + "@ngtools/webpack": "18.0.2", + "@vitejs/plugin-basic-ssl": "1.1.0", "ansi-colors": "4.1.3", - "babel-loader": "8.2.5", + "autoprefixer": "10.4.19", + "babel-loader": "9.1.3", "babel-plugin-istanbul": "6.1.1", - "browserslist": "^4.9.1", - "cacache": "16.1.1", + "browserslist": "^4.21.5", "copy-webpack-plugin": "11.0.0", - "critters": "0.0.16", - "css-loader": "6.7.1", - "esbuild-wasm": "0.14.49", - "glob": "8.0.3", - "https-proxy-agent": "5.0.1", - "inquirer": "8.2.4", - "jsonc-parser": "3.1.0", + "critters": "0.0.22", + "css-loader": "7.1.1", + "esbuild-wasm": "0.21.3", + "fast-glob": "3.3.2", + "http-proxy-middleware": "3.0.0", + "https-proxy-agent": "7.0.4", + "inquirer": "9.2.22", + "jsonc-parser": "3.2.1", "karma-source-map-support": "1.4.0", - "less": "4.1.3", - "less-loader": "11.0.0", + "less": "4.2.0", + "less-loader": "12.2.0", "license-webpack-plugin": "4.0.2", - "loader-utils": "3.2.0", - "mini-css-extract-plugin": "2.6.1", - "minimatch": "5.1.0", - "open": "8.4.0", + "loader-utils": "3.2.1", + "magic-string": "0.30.10", + "mini-css-extract-plugin": "2.9.0", + "mrmime": "2.0.0", + "open": "8.4.2", "ora": "5.4.1", - "parse5-html-rewriting-stream": "6.0.1", - "piscina": "3.2.0", - "postcss": "8.4.14", - "postcss-import": "14.1.0", - "postcss-loader": "7.0.1", - "postcss-preset-env": "7.7.2", - "regenerator-runtime": "0.13.9", + "parse5-html-rewriting-stream": "7.0.0", + "picomatch": "4.0.2", + "piscina": "4.5.0", + "postcss": "8.4.38", + "postcss-loader": "8.1.1", "resolve-url-loader": "5.0.0", - "rxjs": "6.6.7", - "sass": "1.53.0", - "sass-loader": "13.0.2", - "semver": "7.3.7", - "source-map-loader": "4.0.0", + "rxjs": "7.8.1", + "sass": "1.77.2", + "sass-loader": "14.2.1", + "semver": "7.6.2", + "source-map-loader": "5.0.0", "source-map-support": "0.5.21", - "stylus": "0.58.1", - "stylus-loader": "7.0.0", - "terser": "5.14.2", - "text-table": "0.2.0", + "terser": "5.31.0", "tree-kill": "1.2.2", - "tslib": "2.4.0", - "webpack": "5.73.0", - "webpack-dev-middleware": "5.3.3", - "webpack-dev-server": "4.9.3", - "webpack-merge": "5.8.0", + "tslib": "2.6.2", + "undici": "6.18.0", + "vite": "5.2.11", + "watchpack": "2.4.1", + "webpack": "5.91.0", + "webpack-dev-middleware": "7.2.1", + "webpack-dev-server": "5.0.4", + "webpack-merge": "5.10.0", "webpack-subresource-integrity": "5.1.0" }, "engines": { - "node": "^14.15.0 || >=16.10.0", + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" }, "optionalDependencies": { - "esbuild": "0.14.49" + "esbuild": "0.21.3" }, "peerDependencies": { - "@angular/compiler-cli": "^14.0.0", - "@angular/localize": "^14.0.0", - "@angular/service-worker": "^14.0.0", + "@angular/compiler-cli": "^18.0.0", + "@angular/localize": "^18.0.0", + "@angular/platform-server": "^18.0.0", + "@angular/service-worker": "^18.0.0", + "@web/test-runner": "^0.18.0", + "browser-sync": "^3.0.2", + "jest": "^29.5.0", + "jest-environment-jsdom": "^29.5.0", "karma": "^6.3.0", - "ng-packagr": "^14.0.0", + "ng-packagr": "^18.0.0", "protractor": "^7.0.0", "tailwindcss": "^2.0.0 || ^3.0.0", - "typescript": ">=4.6.2 <4.8" + "typescript": ">=5.4 <5.5" }, "peerDependenciesMeta": { "@angular/localize": { "optional": true }, + "@angular/platform-server": { + "optional": true + }, "@angular/service-worker": { "optional": true }, + "@web/test-runner": { + "optional": true + }, + "browser-sync": { + "optional": true + }, + "jest": { + "optional": true + }, + "jest-environment-jsdom": { + "optional": true + }, "karma": { "optional": true }, @@ -251,143 +237,97 @@ } } }, - "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/architect": { - "version": "0.1401.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1401.3.tgz", - "integrity": "sha512-DQvKfl8Q9c02jpGqZX1nOL4mAnRBU6BSqPlhi1q17ZrB8sQpYtDBb8Epn2DDq48l7SQVFnRg6Zgje9L1LObURg==", - "dev": true, - "dependencies": { - "@angular-devkit/core": "14.1.3", - "rxjs": "6.6.7" - }, - "engines": { - "node": "^14.15.0 || >=16.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.1.3.tgz", - "integrity": "sha512-YBxhRl7hKgirjcKeurfejVrIgmw31GcfKKCyQiIudoLCYjonnSMdDEx2y8BNMANvxe5YmuZsIYJtgVlqp3mMDg==", + "node_modules/@angular-devkit/build-angular/node_modules/@babel/core": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.5.tgz", + "integrity": "sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==", "dev": true, "dependencies": { - "ajv": "8.11.0", - "ajv-formats": "2.1.1", - "jsonc-parser": "3.1.0", - "rxjs": "6.6.7", - "source-map": "0.7.4" + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.24.5", + "@babel/helpers": "^7.24.5", + "@babel/parser": "^7.24.5", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.5", + "@babel/types": "^7.24.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" }, "engines": { - "node": "^14.15.0 || >=16.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^3.5.2" + "node": ">=6.9.0" }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "node_modules/@angular-devkit/build-angular/node_modules/postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "node_modules/@angular-devkit/build-angular/node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], - "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@angular-devkit/build-angular/node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "node_modules/@angular-devkit/build-angular/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/@angular-devkit/build-angular/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "dependencies": { - "tslib": "^1.9.0" + "bin": { + "semver": "bin/semver.js" }, "engines": { - "npm": ">=2.0.0" + "node": ">=10" } }, - "node_modules/@angular-devkit/build-angular/node_modules/rxjs/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/@angular-devkit/build-angular/node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", - "dev": true - }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1401.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1401.3.tgz", - "integrity": "sha512-CCKinKF1JNy/cDE5Psn1N4Tl18k9eecDXJUhL4uix3DUHpP3qsVRta8sVJrmE4a3z8DYN6MCw6M38GRzOZiXCQ==", + "version": "0.1800.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1800.2.tgz", + "integrity": "sha512-CbTURBhZWzx+5KewS2Nkqy2rwBTFgDCvUwONGWuy1K68+85vOWUKqjkfvriHA+JkWN03w7FzWEtTfcOg0EzYkw==", "dev": true, "dependencies": { - "@angular-devkit/architect": "0.1401.3", - "rxjs": "6.6.7" + "@angular-devkit/architect": "0.1800.2", + "rxjs": "7.8.1" }, "engines": { - "node": "^14.15.0 || >=16.10.0", + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" }, "peerDependencies": { "webpack": "^5.30.0", - "webpack-dev-server": "^4.0.0" - } - }, - "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/architect": { - "version": "0.1401.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1401.3.tgz", - "integrity": "sha512-DQvKfl8Q9c02jpGqZX1nOL4mAnRBU6BSqPlhi1q17ZrB8sQpYtDBb8Epn2DDq48l7SQVFnRg6Zgje9L1LObURg==", - "dev": true, - "dependencies": { - "@angular-devkit/core": "14.1.3", - "rxjs": "6.6.7" - }, - "engines": { - "node": "^14.15.0 || >=16.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "webpack-dev-server": "^5.0.2" } }, - "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/core": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.1.3.tgz", - "integrity": "sha512-YBxhRl7hKgirjcKeurfejVrIgmw31GcfKKCyQiIudoLCYjonnSMdDEx2y8BNMANvxe5YmuZsIYJtgVlqp3mMDg==", + "node_modules/@angular-devkit/core": { + "version": "18.0.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.0.2.tgz", + "integrity": "sha512-QXcEdfmODc0rKblBerk30yw70fypIkFm6gQBLJgsshpwc+TMA+fuMLcPQebOTzKLtD2tNUkk/7SrWPQIGqeXaA==", "dev": true, "dependencies": { - "ajv": "8.11.0", - "ajv-formats": "2.1.1", - "jsonc-parser": "3.1.0", - "rxjs": "6.6.7", + "ajv": "8.13.0", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.2.1", + "picomatch": "4.0.2", + "rxjs": "7.8.1", "source-map": "0.7.4" }, "engines": { - "node": "^14.15.0 || >=16.10.0", + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" }, @@ -400,377 +340,386 @@ } } }, - "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/@angular-devkit/build-webpack/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/@angular-devkit/core": { - "version": "14.2.13", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.2.13.tgz", - "integrity": "sha512-aIefeZcbjghQg/V6U9CTLtyB5fXDJ63KwYqVYkWP+i0XriS5A9puFgq2u/OVsWxAfYvqpDqp5AdQ0g0bi3CAsA==", + "node_modules/@angular-devkit/core/node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", "dev": true, "dependencies": { - "ajv": "8.11.0", - "ajv-formats": "2.1.1", - "jsonc-parser": "3.1.0", - "rxjs": "6.6.7", - "source-map": "0.7.4" - }, - "engines": { - "node": "^14.15.0 || >=16.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "ajv": "^8.0.0" }, "peerDependencies": { - "chokidar": "^3.5.2" + "ajv": "^8.0.0" }, "peerDependenciesMeta": { - "chokidar": { + "ajv": { "optional": true } } }, - "node_modules/@angular-devkit/core/node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/@angular-devkit/core/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, "node_modules/@angular-devkit/schematics": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-14.1.3.tgz", - "integrity": "sha512-i1vuuClGvBzmgQi3qAUWTwLdnGJZ/C8xVeFMHXmgVNZhck9/8xGGusi500SYsGcVzEfetGSJt5hOfUHmVrcpbg==", + "version": "18.0.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.0.2.tgz", + "integrity": "sha512-G9yGcoB67sH0eRNWoiQWNn2KwiI7sDasVscYPGKf1yo7JRiXmzX/LpfKRPsZTl+Bs0FItnwDInsqgMisK89/6g==", "dev": true, "dependencies": { - "@angular-devkit/core": "14.1.3", - "jsonc-parser": "3.1.0", - "magic-string": "0.26.2", + "@angular-devkit/core": "18.0.2", + "jsonc-parser": "3.2.1", + "magic-string": "0.30.10", "ora": "5.4.1", - "rxjs": "6.6.7" - }, - "engines": { - "node": "^14.15.0 || >=16.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular-devkit/schematics/node_modules/@angular-devkit/core": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.1.3.tgz", - "integrity": "sha512-YBxhRl7hKgirjcKeurfejVrIgmw31GcfKKCyQiIudoLCYjonnSMdDEx2y8BNMANvxe5YmuZsIYJtgVlqp3mMDg==", - "dev": true, - "dependencies": { - "ajv": "8.11.0", - "ajv-formats": "2.1.1", - "jsonc-parser": "3.1.0", - "rxjs": "6.6.7", - "source-map": "0.7.4" + "rxjs": "7.8.1" }, "engines": { - "node": "^14.15.0 || >=16.10.0", + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^3.5.2" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@angular-devkit/schematics/node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" } }, - "node_modules/@angular-devkit/schematics/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, "node_modules/@angular-eslint/builder": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-14.0.4.tgz", - "integrity": "sha512-TUKBGFA5B+jPMnty19Jh6znNhG9ZjKfVzP9oajIU5L+3zThOr+81hzPmcJw6vWsH7nrbkNEEmCQmgKpCCoaYZg==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-18.3.1.tgz", + "integrity": "sha512-cPc7Ye9zDs5M4i+feL6vob+mh7yX5vxvOS5KQIhneUrp5e9D+IGuNFMmBLlOPpmklSc9XJBtuvI5Zjuh4z1ETw==", "dev": true, - "dependencies": { - "@nrwl/devkit": "^14.6.5", - "nx": "^14.6.5" - }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "node_modules/@angular-eslint/bundled-angular-compiler": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-14.0.4.tgz", - "integrity": "sha512-/fbXDvkm4q95xG/9LZDtiyE2MQwT061sanmMginDk63f0dlC4H+AXgggva38YNRN+CFcbFtWfikTy7yFdNFZlA==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-18.3.1.tgz", + "integrity": "sha512-sikmkjfsXPpPTku1aQkQ1MNNEKGBgGGRvUN/WeNS9dhCJ4dxU3O7dZctt1aQWj+W3nbuUtDiimAWF5fZHGFE2Q==", "dev": true }, "node_modules/@angular-eslint/eslint-plugin": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-14.0.4.tgz", - "integrity": "sha512-sPEXAZ/+u0jL849HV1dsc9C15zsiEiOd0Fo5St2YhZuCNsn94kg5zyai5p85/5tbpM6vchaH9cB4fZ3WE+FOog==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-18.3.1.tgz", + "integrity": "sha512-MP4Nm+SHboF8KdnN0KpPEGAaTTzDLPm3+S/4W3Mg8onqWCyadyd4mActh9mK/pvCj8TVlb/SW1zeTtdMYhwonw==", "dev": true, "dependencies": { - "@angular-eslint/utils": "14.0.4", - "@typescript-eslint/utils": "5.36.2" + "@angular-eslint/bundled-angular-compiler": "18.3.1", + "@angular-eslint/utils": "18.3.1" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0", + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "node_modules/@angular-eslint/eslint-plugin-template": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-14.0.4.tgz", - "integrity": "sha512-F3GgItYHcEtQfOcJoyfvmRKdFIrI+/Wc7SjOo1X31tdeaQaRHseYWGFZ5AaA+MM+/rV7jPAd671Tv7wlm+Wjtg==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-18.3.1.tgz", + "integrity": "sha512-hBJ3+f7VSidvrtYaXH7Vp0sWvblA9jLK2c6uQzhYGWdEDUcTg7g7VI9ThW39WvMbHqkyzNE4PPOynK69cBEDGg==", "dev": true, "dependencies": { - "@angular-eslint/bundled-angular-compiler": "14.0.4", - "@typescript-eslint/type-utils": "5.36.2", - "@typescript-eslint/utils": "5.36.2", - "aria-query": "5.0.2", - "axobject-query": "3.0.1" + "@angular-eslint/bundled-angular-compiler": "18.3.1", + "@angular-eslint/utils": "18.3.1", + "aria-query": "5.3.0", + "axobject-query": "4.1.0" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0", + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "node_modules/@angular-eslint/schematics": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-14.0.4.tgz", - "integrity": "sha512-Yg1bQhJa5VTlGOMHcczXvLDn5t+NimK2Wczy9T+QHmBdFf1GQWb6lOxJmgFTr3sFlC2sGXcP0N1AUikO4n0f/Q==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-18.3.1.tgz", + "integrity": "sha512-BTsQHDu7LjvXannJTb5BqMPCFIHRNN94eRyb60VfjJxB/ZFtsbAQDFFOi5lEZsRsd4mBeUMuL9mW4IMcPtUQ9Q==", "dev": true, "dependencies": { - "@angular-eslint/eslint-plugin": "14.0.4", - "@angular-eslint/eslint-plugin-template": "14.0.4", - "ignore": "5.2.0", - "strip-json-comments": "3.1.1", - "tmp": "0.2.1" + "@angular-eslint/eslint-plugin": "18.3.1", + "@angular-eslint/eslint-plugin-template": "18.3.1", + "ignore": "5.3.2", + "semver": "7.6.3", + "strip-json-comments": "3.1.1" }, "peerDependencies": { - "@angular/cli": ">= 14.0.0 < 15.0.0" + "@angular-devkit/core": ">= 18.0.0 < 19.0.0", + "@angular-devkit/schematics": ">= 18.0.0 < 19.0.0" } }, "node_modules/@angular-eslint/template-parser": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-14.0.4.tgz", - "integrity": "sha512-L7+VHWlIUiUml81q43tP/CZZhIDkbHoin2OH+0TEqeQuCcYZwZQfUBey0pmbzzhjZD2tV75QxlAUqFCuM85Tng==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-18.3.1.tgz", + "integrity": "sha512-JUUkfWH1G+u/Uk85ZYvJSt/qwN/Ko+jlXFtzBEcknJZsTWTwBcp36v77gPZe5FmKSziJZpyPUd+7Kiy6tuSCTw==", "dev": true, "dependencies": { - "@angular-eslint/bundled-angular-compiler": "14.0.4", - "eslint-scope": "^5.1.0" + "@angular-eslint/bundled-angular-compiler": "18.3.1", + "eslint-scope": "^8.0.2" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, - "node_modules/@angular-eslint/utils": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-14.0.4.tgz", - "integrity": "sha512-7BcK+g0qaMRXfRFeOf57UOb5R4V8/uzGLyeXkugA65s7BLDLPEV1StRTpGW7w4jK7I8sldfsnbrkJqb6hgQtfA==", + "node_modules/@angular-eslint/template-parser/node_modules/eslint-scope": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.1.0.tgz", + "integrity": "sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==", "dev": true, "dependencies": { - "@angular-eslint/bundled-angular-compiler": "14.0.4", - "@typescript-eslint/utils": "5.36.2" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0", - "typescript": "*" - } - }, - "node_modules/@angular/animations": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-14.1.3.tgz", - "integrity": "sha512-AmnrsRWJxlIQPnnef3MCo9N7bbFmEWvyyDPB8z4UOYDqBwRBHnDn5g1rrVQzLJH7I1O2DLcm/EhWYJrfagQ2aQ==", - "dependencies": { - "tslib": "^2.3.0" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": "^14.15.0 || >=16.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependencies": { - "@angular/core": "14.1.3" + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@angular/cdk": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-14.1.3.tgz", - "integrity": "sha512-NCdBkgnBgZvA4wZ6wXu/T3l4CgmWOs3M5NFKqQ/G2DCVfIbwaTI3G5cSNk6M63geeGwWDaMkk2Uxjgy4qyvaww==", - "dependencies": { - "tslib": "^2.3.0" - }, - "optionalDependencies": { - "parse5": "^5.0.0" - }, - "peerDependencies": { - "@angular/common": "^14.0.0 || ^15.0.0", - "@angular/core": "^14.0.0 || ^15.0.0", - "rxjs": "^6.5.3 || ^7.4.0" + "node_modules/@angular-eslint/template-parser/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" } }, - "node_modules/@angular/cli": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-14.1.3.tgz", - "integrity": "sha512-JAvxOXXGf4VCJUQLe3g0pDNnOnE5E7tJfhqsn77+TGrhFpYPMmZ8z747ohiFXrTqbSe0dWTwOfqwpAA41R1CeA==", + "node_modules/@angular-eslint/utils": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-18.3.1.tgz", + "integrity": "sha512-sd9niZI7h9H2FQ7OLiQsLFBhjhRQTASh+Q0+4+hyjv9idbSHBJli8Gsi2fqj9zhtMKpAZFTrWzuLUpubJ9UYbA==", "dev": true, "dependencies": { - "@angular-devkit/architect": "0.1401.3", - "@angular-devkit/core": "14.1.3", - "@angular-devkit/schematics": "14.1.3", - "@schematics/angular": "14.1.3", - "@yarnpkg/lockfile": "1.1.0", - "ansi-colors": "4.1.3", - "debug": "4.3.4", - "ini": "3.0.0", - "inquirer": "8.2.4", - "jsonc-parser": "3.1.0", - "npm-package-arg": "9.1.0", - "npm-pick-manifest": "7.0.1", - "open": "8.4.0", - "ora": "5.4.1", - "pacote": "13.6.1", - "resolve": "1.22.1", - "semver": "7.3.7", - "symbol-observable": "4.0.0", - "uuid": "8.3.2", - "yargs": "17.5.1" - }, - "bin": { - "ng": "bin/ng.js" + "@angular-eslint/bundled-angular-compiler": "18.3.1" }, - "engines": { - "node": "^14.15.0 || >=16.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "peerDependencies": { + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" } }, - "node_modules/@angular/cli/node_modules/@angular-devkit/architect": { - "version": "0.1401.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1401.3.tgz", - "integrity": "sha512-DQvKfl8Q9c02jpGqZX1nOL4mAnRBU6BSqPlhi1q17ZrB8sQpYtDBb8Epn2DDq48l7SQVFnRg6Zgje9L1LObURg==", - "dev": true, + "node_modules/@angular/animations": { + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.0.1.tgz", + "integrity": "sha512-QAY/oxfuFY2Bjr3foniWlLAiddXHu8879lZvXHt1NVOsiav+vD15IEEQsnuQbJPy/EHEnAlUh9UptB4zQIBp/Q==", "dependencies": { - "@angular-devkit/core": "14.1.3", - "rxjs": "6.6.7" + "tslib": "^2.3.0" }, "engines": { - "node": "^14.15.0 || >=16.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/core": "18.0.1" } }, - "node_modules/@angular/cli/node_modules/@angular-devkit/core": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.1.3.tgz", - "integrity": "sha512-YBxhRl7hKgirjcKeurfejVrIgmw31GcfKKCyQiIudoLCYjonnSMdDEx2y8BNMANvxe5YmuZsIYJtgVlqp3mMDg==", + "node_modules/@angular/build": { + "version": "18.0.2", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.0.2.tgz", + "integrity": "sha512-iPPHdAJ3LiR8t/+39xjvrqMWcTmRrfphzKxXoIVDcswQjVQIk00EYuxinC6EVa7dSKDl1thk1MeCNZ9DIjaAvQ==", "dev": true, "dependencies": { - "ajv": "8.11.0", - "ajv-formats": "2.1.1", - "jsonc-parser": "3.1.0", - "rxjs": "6.6.7", - "source-map": "0.7.4" + "@ampproject/remapping": "2.3.0", + "@angular-devkit/architect": "0.1800.2", + "@babel/core": "7.24.5", + "@babel/helper-annotate-as-pure": "7.22.5", + "@babel/helper-split-export-declaration": "7.24.5", + "@vitejs/plugin-basic-ssl": "1.1.0", + "ansi-colors": "4.1.3", + "browserslist": "^4.23.0", + "critters": "0.0.22", + "esbuild": "0.21.3", + "fast-glob": "3.3.2", + "https-proxy-agent": "7.0.4", + "inquirer": "9.2.22", + "lmdb": "3.0.8", + "magic-string": "0.30.10", + "mrmime": "2.0.0", + "ora": "5.4.1", + "parse5-html-rewriting-stream": "7.0.0", + "picomatch": "4.0.2", + "piscina": "4.5.0", + "sass": "1.77.2", + "semver": "7.6.2", + "undici": "6.18.0", + "vite": "5.2.11", + "watchpack": "2.4.1" }, "engines": { - "node": "^14.15.0 || >=16.10.0", + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" }, "peerDependencies": { - "chokidar": "^3.5.2" + "@angular/compiler-cli": "^18.0.0", + "@angular/localize": "^18.0.0", + "@angular/platform-server": "^18.0.0", + "@angular/service-worker": "^18.0.0", + "less": "^4.2.0", + "postcss": "^8.4.0", + "tailwindcss": "^2.0.0 || ^3.0.0", + "typescript": ">=5.4 <5.5" }, "peerDependenciesMeta": { - "chokidar": { + "@angular/localize": { + "optional": true + }, + "@angular/platform-server": { + "optional": true + }, + "@angular/service-worker": { + "optional": true + }, + "less": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tailwindcss": { "optional": true } } }, - "node_modules/@angular/cli/node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "node_modules/@angular/build/node_modules/@babel/core": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.5.tgz", + "integrity": "sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==", "dev": true, "dependencies": { - "tslib": "^1.9.0" + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.24.5", + "@babel/helpers": "^7.24.5", + "@babel/parser": "^7.24.5", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.5", + "@babel/types": "^7.24.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" }, "engines": { - "npm": ">=2.0.0" + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@angular/build/node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@angular/build/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/@angular/build/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular/cdk": { + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-18.0.1.tgz", + "integrity": "sha512-2fCqX1sz5cM+LncO6ak4EU2ZBm8MWitv5V53go3Iz5dOVOdrvysBt8smEkWZ4nvEKkFYHEPpQo0YlxEWbuTEmA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "optionalDependencies": { + "parse5": "^7.1.2" + }, + "peerDependencies": { + "@angular/common": "^18.0.0 || ^19.0.0", + "@angular/core": "^18.0.0 || ^19.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/cli": { + "version": "18.0.2", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-18.0.2.tgz", + "integrity": "sha512-shrxMD1bcWWh7WpBN3KTV+Lt8E62gURSUFhs6kdGLepMDif8LPAv45+hpt8SBU9VfQuL6AHa4cW8uDL9BKGlYA==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "0.1800.2", + "@angular-devkit/core": "18.0.2", + "@angular-devkit/schematics": "18.0.2", + "@schematics/angular": "18.0.2", + "@yarnpkg/lockfile": "1.1.0", + "ansi-colors": "4.1.3", + "ini": "4.1.2", + "inquirer": "9.2.22", + "jsonc-parser": "3.2.1", + "npm-package-arg": "11.0.2", + "npm-pick-manifest": "9.0.1", + "ora": "5.4.1", + "pacote": "18.0.6", + "resolve": "1.22.8", + "semver": "7.6.2", + "symbol-observable": "4.0.0", + "yargs": "17.7.2" + }, + "bin": { + "ng": "bin/ng.js" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/cli/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "node_modules/@angular/cli/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, "node_modules/@angular/common": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-14.1.3.tgz", - "integrity": "sha512-t5zidNLcQrgrShBFFsEhvJ6yKw5jwv/Td/AQrknQzrAz3kVBH4dOZGC5jolasFipy/P1DNoG2K+igPCGeskc4w==", + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-18.0.1.tgz", + "integrity": "sha512-iADQC5m4fvk+VNXEoU1KR93b0eG218/GuNdzUNVJHcjxdFxPshKk5fiaGSosUCxXPRQOxDKzmS9EDang87E/Ew==", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^14.15.0 || >=16.10.0" + "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/core": "14.1.3", + "@angular/core": "18.0.1", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-14.1.3.tgz", - "integrity": "sha512-QtBHzhGzym8CwGrZLFYsciaLq/F4lxUxNOBDQdrc5Pd/qYiaJ50rrWfmXpqrFR6CC0E0bgzIj0Uxdf+D/VRmWQ==", + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-18.0.1.tgz", + "integrity": "sha512-zyG/ifCtN0drAuwz0oV6LtzTiDREsM1Ay7eJW9wTvp3NCv06goHLtHXX12eFfZQWJViBv924lyRDSWdZN7r3GQ==", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^14.15.0 || >=16.10.0" + "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/core": "14.1.3" + "@angular/core": "18.0.1" }, "peerDependenciesMeta": { "@angular/core": { @@ -779,208 +728,157 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-14.1.3.tgz", - "integrity": "sha512-GJqUfIKuM7bYeR699ceRSa6LT90vEi2q+s+YIwRrlXSFto7xNCmn5bJsYV6XmslvPPTqiLR5w9K8MNC9qYBbxw==", + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-18.0.1.tgz", + "integrity": "sha512-Aoz70+/o8R2lG2EGDAYbj6yu2B7kqa/9loYEwG0fECJTtXoRBP+bEGpUxMmxOb59tMDnbIhBHmNPPEQVTXvgSQ==", + "dev": true, "dependencies": { - "@babel/core": "^7.17.2", + "@babel/core": "7.24.4", + "@jridgewell/sourcemap-codec": "^1.4.14", "chokidar": "^3.0.0", "convert-source-map": "^1.5.1", - "dependency-graph": "^0.11.0", - "magic-string": "^0.26.0", - "reflect-metadata": "^0.1.2", + "reflect-metadata": "^0.2.0", "semver": "^7.0.0", - "sourcemap-codec": "^1.4.8", "tslib": "^2.3.0", "yargs": "^17.2.1" }, "bin": { "ng-xi18n": "bundles/src/bin/ng_xi18n.js", "ngc": "bundles/src/bin/ngc.js", - "ngcc": "bundles/ngcc/main-ngcc.js" + "ngcc": "bundles/ngcc/index.js" }, "engines": { - "node": "^14.15.0 || >=16.10.0" + "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/compiler": "14.1.3", - "typescript": ">=4.6.2 <4.8" + "@angular/compiler": "18.0.1", + "typescript": ">=5.4 <5.5" } }, "node_modules/@angular/core": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-14.1.3.tgz", - "integrity": "sha512-V3OJD4cShjLzyJAWQ1ogSW0WhKJwti5zsoT1SQ2RoA5UScBPzZN/F/0n/4IupHeaIC+NfaLX916xKTGWA8G8SQ==", + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.0.1.tgz", + "integrity": "sha512-Db1livvugoLdLsWww5IqUS5v+yUN7/5Rj0trZv9BgxIuoNtoipfLqKHwZWpumH3yI5Ucu+UH9zZ1mlGyF0Kexw==", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^14.15.0 || >=16.10.0" + "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { "rxjs": "^6.5.3 || ^7.4.0", - "zone.js": "~0.11.4" - } - }, - "node_modules/@angular/flex-layout": { - "version": "14.0.0-beta.41", - "resolved": "https://registry.npmjs.org/@angular/flex-layout/-/flex-layout-14.0.0-beta.41.tgz", - "integrity": "sha512-x1YcxqkdFlcbVXEy9ebCgW/F+7n/MXkEkwEcVEIPf5v5qn7HZsjQxgIj35Lf0amvMyF7h35prpoxO1uX5+ntFg==", - "deprecated": "This package has been deprecated. Please see https://blog.angular.io/modern-css-in-angular-layouts-4a259dca9127", - "dependencies": { - "tslib": "^2.3.0" - }, - "peerDependencies": { - "@angular/cdk": "^14.0.0", - "@angular/common": "^14.0.0", - "@angular/core": "^14.0.0", - "@angular/platform-browser": "^14.0.0", - "rxjs": "^6.5.3 || ^7.4.0" + "zone.js": "~0.14.0" } }, "node_modules/@angular/forms": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-14.1.3.tgz", - "integrity": "sha512-gCN3my9KRp6BLlBGh4uw8NukUPKCl+quroMO2lkvsodF0MA42uhKHO+EImrpLxNMK7lfENIERwthb4mh4G4cFQ==", + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-18.0.1.tgz", + "integrity": "sha512-j1nUzwnZHO/BRXK0joQbAV10JWxeRVKmPzIaDulY2o28Er1jVKyw2T8EwI+xSvBbAqyJyaAd+ysWUhm3FfH+GA==", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^14.15.0 || >=16.10.0" + "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/common": "14.1.3", - "@angular/core": "14.1.3", - "@angular/platform-browser": "14.1.3", + "@angular/common": "18.0.1", + "@angular/core": "18.0.1", + "@angular/platform-browser": "18.0.1", "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@angular/language-service": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-14.1.3.tgz", - "integrity": "sha512-7XEvRFzApFr6TtyCysGrleerClcU9ldCGoZsDL5SOUEL+3IEPC5L3uJYExLon30pu9jne9Sxq0w8u4cv/rYIeA==", - "dev": true, - "engines": { - "node": "^14.15.0 || >=16.10.0" - } - }, - "node_modules/@angular/localize": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-14.1.3.tgz", - "integrity": "sha512-u6llXXTm7WAPAjg2jbqgKMHkquVP0dT9LI92hc91gX8HSbojSNYK2Hsx6QJ2VWOpjXxfc13W5IMhp2G6u29urw==", - "dependencies": { - "@babel/core": "7.18.9", - "glob": "8.0.3", - "yargs": "^17.2.1" - }, - "bin": { - "localize-extract": "tools/bundles/src/extract/cli.js", - "localize-migrate": "tools/bundles/src/migrate/cli.js", - "localize-translate": "tools/bundles/src/translate/cli.js" - }, - "engines": { - "node": "^14.15.0 || >=16.10.0" + "node_modules/@angular/material": { + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-18.0.1.tgz", + "integrity": "sha512-y8OaESXw32P74Jh2FEr3n7QjqjTlo2Jf+XdgOvp5dd1yxpJ20vnK7ZCEQqCpxdxGAzXqR+2DccKk9tebB9egZw==", + "dependencies": { + "@material/animation": "15.0.0-canary.7f224ddd4.0", + "@material/auto-init": "15.0.0-canary.7f224ddd4.0", + "@material/banner": "15.0.0-canary.7f224ddd4.0", + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/button": "15.0.0-canary.7f224ddd4.0", + "@material/card": "15.0.0-canary.7f224ddd4.0", + "@material/checkbox": "15.0.0-canary.7f224ddd4.0", + "@material/chips": "15.0.0-canary.7f224ddd4.0", + "@material/circular-progress": "15.0.0-canary.7f224ddd4.0", + "@material/data-table": "15.0.0-canary.7f224ddd4.0", + "@material/density": "15.0.0-canary.7f224ddd4.0", + "@material/dialog": "15.0.0-canary.7f224ddd4.0", + "@material/dom": "15.0.0-canary.7f224ddd4.0", + "@material/drawer": "15.0.0-canary.7f224ddd4.0", + "@material/elevation": "15.0.0-canary.7f224ddd4.0", + "@material/fab": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/floating-label": "15.0.0-canary.7f224ddd4.0", + "@material/form-field": "15.0.0-canary.7f224ddd4.0", + "@material/icon-button": "15.0.0-canary.7f224ddd4.0", + "@material/image-list": "15.0.0-canary.7f224ddd4.0", + "@material/layout-grid": "15.0.0-canary.7f224ddd4.0", + "@material/line-ripple": "15.0.0-canary.7f224ddd4.0", + "@material/linear-progress": "15.0.0-canary.7f224ddd4.0", + "@material/list": "15.0.0-canary.7f224ddd4.0", + "@material/menu": "15.0.0-canary.7f224ddd4.0", + "@material/menu-surface": "15.0.0-canary.7f224ddd4.0", + "@material/notched-outline": "15.0.0-canary.7f224ddd4.0", + "@material/radio": "15.0.0-canary.7f224ddd4.0", + "@material/ripple": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/segmented-button": "15.0.0-canary.7f224ddd4.0", + "@material/select": "15.0.0-canary.7f224ddd4.0", + "@material/shape": "15.0.0-canary.7f224ddd4.0", + "@material/slider": "15.0.0-canary.7f224ddd4.0", + "@material/snackbar": "15.0.0-canary.7f224ddd4.0", + "@material/switch": "15.0.0-canary.7f224ddd4.0", + "@material/tab": "15.0.0-canary.7f224ddd4.0", + "@material/tab-bar": "15.0.0-canary.7f224ddd4.0", + "@material/tab-indicator": "15.0.0-canary.7f224ddd4.0", + "@material/tab-scroller": "15.0.0-canary.7f224ddd4.0", + "@material/textfield": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/tokens": "15.0.0-canary.7f224ddd4.0", + "@material/tooltip": "15.0.0-canary.7f224ddd4.0", + "@material/top-app-bar": "15.0.0-canary.7f224ddd4.0", + "@material/touch-target": "15.0.0-canary.7f224ddd4.0", + "@material/typography": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.3.0" }, "peerDependencies": { - "@angular/compiler": "14.1.3", - "@angular/compiler-cli": "14.1.3" - } - }, - "node_modules/@angular/localize/node_modules/@babel/core": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.9.tgz", - "integrity": "sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g==", - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.18.9", - "@babel/helper-compilation-targets": "^7.18.9", - "@babel/helper-module-transforms": "^7.18.9", - "@babel/helpers": "^7.18.9", - "@babel/parser": "^7.18.9", - "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.9", - "@babel/types": "^7.18.9", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@angular/localize/node_modules/@babel/generator": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.8.tgz", - "integrity": "sha512-47DG+6F5SzOi0uEvK4wMShmn5yY0mVjVJoWTphdY2B4Rx9wHgjK7Yhtr0ru6nE+sn0v38mzrWOlah0p/YlHHOQ==", - "dependencies": { - "@babel/types": "^7.24.8", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@angular/localize/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@angular/localize/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" + "@angular/animations": "^18.0.0 || ^19.0.0", + "@angular/cdk": "18.0.1", + "@angular/common": "^18.0.0 || ^19.0.0", + "@angular/core": "^18.0.0 || ^19.0.0", + "@angular/forms": "^18.0.0 || ^19.0.0", + "@angular/platform-browser": "^18.0.0 || ^19.0.0", + "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@angular/material": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-14.1.3.tgz", - "integrity": "sha512-vGznrsO1fLvXZ33Z/A+4/EUHu170V5+jMvL3/K5EJypi2Xms4neHWec+NH1Ear7dFr8buhDBCIGTO1vAPJEleQ==", + "node_modules/@angular/material-luxon-adapter": { + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/@angular/material-luxon-adapter/-/material-luxon-adapter-18.0.1.tgz", + "integrity": "sha512-gmcn95t4rIQIXdpcmjXr1AL/Wp/m0+A+SAZ/sYduo7iCBvQX9VO4se70xx1PULgAvS1AmijEUmAW5tDwxzTJvQ==", "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { - "@angular/animations": "^14.0.0 || ^15.0.0", - "@angular/cdk": "14.1.3", - "@angular/common": "^14.0.0 || ^15.0.0", - "@angular/core": "^14.0.0 || ^15.0.0", - "@angular/forms": "^14.0.0 || ^15.0.0", - "@angular/platform-browser": "^14.0.0 || ^15.0.0", - "rxjs": "^6.5.3 || ^7.4.0" + "@angular/core": "^18.0.0 || ^19.0.0", + "@angular/material": "18.0.1", + "luxon": "^3.0.0" } }, "node_modules/@angular/platform-browser": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-14.1.3.tgz", - "integrity": "sha512-baEHBj2pCrz5XR9KCb2FaAChWsRrxl9yapDZFNpApucN/OlQpBDVA9UDDvaYeD3PsI8nVL3B6danKUloamd+pw==", + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-18.0.1.tgz", + "integrity": "sha512-rQUsOxZxiwSPvyHdne60IKIGsvFoVc1rO4mDyXU+9sCCLmPKHzNyEzp7vybTZeiqa3k6v3sV/bfHWwrRzmvenw==", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^14.15.0 || >=16.10.0" + "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/animations": "14.1.3", - "@angular/common": "14.1.3", - "@angular/core": "14.1.3" + "@angular/animations": "18.0.1", + "@angular/common": "18.0.1", + "@angular/core": "18.0.1" }, "peerDependenciesMeta": { "@angular/animations": { @@ -989,51 +887,67 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-14.1.3.tgz", - "integrity": "sha512-WOWMgXUe8dEXt33jCP8/d8O5NQJKyr+4Dq2sjJ7y1ouCOjJsc9Ybi3y5uMyDCwb6SausGWLJ6w7DweMDWMlsYA==", + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-18.0.1.tgz", + "integrity": "sha512-lzjq7HjigGxO5oh5Sw0Vxa3mAVidYHpHFQr46/OSl9T5jLpStcjEqK0xcfQz9bf2hV+0qFfMqmd2k0XQl7feqg==", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^14.15.0 || >=16.10.0" + "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/common": "14.1.3", - "@angular/compiler": "14.1.3", - "@angular/core": "14.1.3", - "@angular/platform-browser": "14.1.3" + "@angular/common": "18.0.1", + "@angular/compiler": "18.0.1", + "@angular/core": "18.0.1", + "@angular/platform-browser": "18.0.1" } }, "node_modules/@angular/router": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-14.1.3.tgz", - "integrity": "sha512-LjWQBaeaGkgFy814booGmQV2eELDynzACGAZUwrpWmdHKo9p9GCi9dYttYXspNDmxoipXAzYvVPSABlMfhuQ+g==", + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-18.0.1.tgz", + "integrity": "sha512-PapdvfATjRZI0cJ/RH8n/ixHDHa4HIBaOMwhgU73InU9t6NIhBXg6aRECYV2qGt7NtpLYSHmG5Z1Ws86rm5Tyw==", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^14.15.0 || >=16.10.0" + "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/common": "14.1.3", - "@angular/core": "14.1.3", - "@angular/platform-browser": "14.1.3", + "@angular/common": "18.0.1", + "@angular/core": "18.0.1", + "@angular/platform-browser": "18.0.1", "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@assemblyscript/loader": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz", - "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==", - "dev": true + "node_modules/@antfu/install-pkg": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-0.4.1.tgz", + "integrity": "sha512-T7yB5QNG29afhWVkVq7XeIMBa5U/vs9mX69YqayXypPRmYzUmzwnYltplHmPtZ4HPCn+sQKeXW8I47wCbuBOjw==", + "optional": true, + "dependencies": { + "package-manager-detector": "^0.2.0", + "tinyexec": "^0.3.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@antfu/utils": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.10.tgz", + "integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==", + "optional": true, + "funding": { + "url": "https://github.com/sponsors/antfu" + } }, "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", "dependencies": { - "@babel/highlight": "^7.24.7", + "@babel/highlight": "^7.24.2", "picocolors": "^1.0.0" }, "engines": { @@ -1041,33 +955,35 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.8.tgz", - "integrity": "sha512-c4IM7OTg6k1Q+AJ153e2mc2QVTezTwnb4VzquwcyiEzGnW0Kedv4do/TrkU98qPeC5LNiMt/QXwIjzYXLBpyZg==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz", + "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==", + "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.6.tgz", - "integrity": "sha512-cQbWBpxcbbs/IUredIPkHiAGULLV8iwgNRMFzvbhEXISp4f3rUUXE5+TIw6KwUWUR3DwyI6gmBRnmAtYaWehwQ==", - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.18.6", - "@babel/helper-compilation-targets": "^7.18.6", - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helpers": "^7.18.6", - "@babel/parser": "^7.18.6", - "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.6", - "@babel/types": "^7.18.6", - "convert-source-map": "^1.7.0", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz", + "integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.4", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", + "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" + "json5": "^2.2.3", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -1077,73 +993,69 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/generator": { - "version": "7.18.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.7.tgz", - "integrity": "sha512-shck+7VLlY72a2w9c3zYWuE1pwOKEiQHV7GTUbSnhyl5eu3i04t30tBY82ZRWrDfo3gkakCFtevExnxbkf2a3A==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.5.tgz", + "integrity": "sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==", + "dev": true, "dependencies": { - "@babel/types": "^7.18.7", - "@jridgewell/gen-mapping": "^0.3.2", + "@babel/types": "^7.24.5", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", - "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", "dev": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", - "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", "dev": true, "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz", - "integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "dev": true, "dependencies": { - "@babel/compat-data": "^7.24.8", - "@babel/helper-validator-option": "^7.24.8", - "browserslist": "^4.23.1", + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -1155,24 +1067,25 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.8.tgz", - "integrity": "sha512-4f6Oqnmyp2PP3olgUMmOwC3akxSm5aBYraQ6YDdKy7NcAMkDECHWG0DEnV6M2UAkERgIBhYt8S27rURPg7SxWA==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-member-expression-to-functions": "^7.24.8", - "@babel/helper-optimise-call-expression": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.5.tgz", + "integrity": "sha512-uRc4Cv8UQWnE4NXlYTIIdM7wfFkOqlFztcC/gVXDKohKoVB3OyonfelUBaJzSwpBntZ2KYGF/9S7asCHsXwW6g==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-member-expression-to-functions": "^7.24.5", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.24.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.24.5", "semver": "^6.3.1" }, "engines": { @@ -1182,18 +1095,6 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/helper-annotate-as-pure": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", - "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -1204,12 +1105,12 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.24.7.tgz", - "integrity": "sha512-03TCmXy2FtXJEZfbXDTSqq1fRJArk7lX9DOFC/47VthYcxyIOx+eXQmdo6DOQvrbpIix+KfXwvuXdFDZHxt+rA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-annotate-as-pure": "^7.22.5", "regexpu-core": "^5.3.1", "semver": "^6.3.1" }, @@ -1220,18 +1121,6 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/@babel/helper-annotate-as-pure": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", - "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -1242,113 +1131,90 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", - "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", + "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" + "resolve": "^1.14.2" }, "peerDependencies": { - "@babel/core": "^7.4.0-0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", - "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", - "dependencies": { - "@babel/types": "^7.24.7" - }, + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", - "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name/node_modules/@babel/template": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", - "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", - "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, "dependencies": { - "@babel/types": "^7.24.7" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", - "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.5.tgz", + "integrity": "sha512-4owRteeihKWKamtqg4JmWSsEZU445xpFRXPEwp44HbgbxdWlUV1b4Agg4lkA806Lil5XM/e+FJyS0vj5T6vmcA==", "dev": true, "dependencies": { - "@babel/traverse": "^7.24.8", - "@babel/types": "^7.24.8" + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", + "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", + "dev": true, "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/types": "^7.24.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.8.tgz", - "integrity": "sha512-m4vWKVqvkVAWLXfHCCfff2luJj86U+J0/x+0N3ArG/tP0Fq7zky2dYwMbtPmkc/oulkkbjdL3uWzuoBwQ8R00Q==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz", + "integrity": "sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A==", + "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.24.3", + "@babel/helper-simple-access": "^7.24.5", + "@babel/helper-split-export-declaration": "^7.24.5", + "@babel/helper-validator-identifier": "^7.24.5" }, "engines": { "node": ">=6.9.0" @@ -1358,35 +1224,35 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", - "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", "dev": true, "dependencies": { - "@babel/types": "^7.24.7" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", - "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz", + "integrity": "sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.24.7.tgz", - "integrity": "sha512-9pKLcTlZ92hNZMQfGCHImUpDOlAgkkpqalWEeftW5FBya75k8Li2ilerxkM/uBEj01iBZXcCIB/bwvDYgWyibA==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-wrap-function": "^7.24.7" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" }, "engines": { "node": ">=6.9.0" @@ -1395,27 +1261,15 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-remap-async-to-generator/node_modules/@babel/helper-annotate-as-pure": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", - "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-replace-supers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.7.tgz", - "integrity": "sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.1.tgz", + "integrity": "sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-member-expression-to-functions": "^7.24.7", - "@babel/helper-optimise-call-expression": "^7.24.7" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1425,125 +1279,101 @@ } }, "node_modules/@babel/helper-simple-access": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", - "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz", + "integrity": "sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ==", + "dev": true, "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", - "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", "dev": true, "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", - "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz", + "integrity": "sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==", + "dev": true, "dependencies": { - "@babel/types": "^7.24.7" + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", - "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", + "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", + "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", - "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.7.tgz", - "integrity": "sha512-N9JIYk3TD+1vq/wn77YnJOqMtfWhNewNE+DJV4puD2X7Ew9J4JvrzrFDfTfyv5EgEXVy9/Wt8QiOErzEmv5Ifw==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", "dev": true, - "dependencies": { - "@babel/helper-function-name": "^7.24.7", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-wrap-function/node_modules/@babel/template": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", - "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", + "node_modules/@babel/helper-wrap-function": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.5.tgz", + "integrity": "sha512-/xxzuNvgRl4/HLNKvnFwdhdgN3cpLxgLROeLDl83Yx0AJ1SGvq1ak0OszTOjDfiB8Vx03eJbeDWh9r+jCCWttw==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/helper-function-name": "^7.23.0", + "@babel/template": "^7.24.0", + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.8.tgz", - "integrity": "sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==", - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.8" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers/node_modules/@babel/template": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", - "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.5.tgz", + "integrity": "sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q==", + "dev": true, "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.5", + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz", + "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==", "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.5", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -1553,9 +1383,10 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz", - "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz", + "integrity": "sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==", + "dev": true, "bin": { "parser": "bin/babel-parser.js" }, @@ -1563,13 +1394,14 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.7.tgz", - "integrity": "sha512-unaQgZ/iRu/By6tsjMZzpeBZjChYfLYry6HrEXPoz3KmfF0sVBQ1l8zKMQ4xRGLWVsjuvB8nQfjNP/DcfEOCsg==", + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.5.tgz", + "integrity": "sha512-LdXRi1wEMTrHVR4Zc9F8OewC3vdm5h4QB6L71zy6StmYeqGi1b3ttIO8UC+BfZKcH9jdr4aI249rBkm+3+YvHw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.24.5" }, "engines": { "node": ">=6.9.0" @@ -1578,306 +1410,73 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", - "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.1.tgz", + "integrity": "sha512-y4HqEnkelJIOQGd+3g1bTeKsA5c6qM7eOn7VggGVbBc0y8MLSKHacwcIE2PplNlQSj0PqS9rrXL/nkPVK+kUNg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.13.0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.6.tgz", - "integrity": "sha512-WAz4R9bvozx4qwf74M+sfqPMKfSqwM0phxPTR6iJIi8robgzXwkEgmeJG1gEKhm6sDqT/U9aV3lfcqybIpev8w==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-async-generator-functions instead.", + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.1.tgz", + "integrity": "sha512-Hj791Ii4ci8HqnaKHAlLNs+zaLXb0EzSDhiAWp5VNlyvCNymYfacs64pxTxbH1znW/NcArSmwpmG9IKE/TUVVQ==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-remap-async-to-generator": "^7.18.6", - "@babel/plugin-syntax-async-generators": "^7.8.4" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.24.1" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.13.0" } }, - "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", - "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.", + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.1.tgz", + "integrity": "sha512-m9m/fXsXLiHfwdgydIFnpk+7jlVbnvlK5B2EKiPdLUb6WX654ZaaEWJUjk8TftRbZpK0XibovlLWX4KIZhV6jw==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-proposal-class-static-block": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.21.0.tgz", - "integrity": "sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-static-block instead.", + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.12.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", - "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-dynamic-import instead.", + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", - "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-export-namespace-from instead.", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", - "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-json-strings instead.", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-json-strings": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", - "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-logical-assignment-operators instead.", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", - "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", - "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-numeric-separator instead.", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", - "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", - "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-catch-binding instead.", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", - "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", - "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-methods instead.", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz", - "integrity": "sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-property-in-object instead.", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", - "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-unicode-property-regex instead.", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" @@ -1935,12 +1534,27 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz", - "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.1.tgz", + "integrity": "sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.1.tgz", + "integrity": "sha512-zhQTMH0X2nVLnb04tz+s7AMuasX8U0FnpE+nHTOhSOINjWMnopoZTxtIKsd45n4GQ/HIZLyfIpoul8e2m0DnRA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2075,13 +1689,29 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz", - "integrity": "sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==", + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.1.tgz", + "integrity": "sha512-ngT/3NkRhsaep9ck9uj2Xhv9+xB1zShY3tM3g6om4xxCELwCDN4g4Aq5dRn48+0hasAql7s2hdBOysCfNpr4fw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2090,13 +1720,16 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", - "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.3.tgz", + "integrity": "sha512-Qe26CMYVjpQxJ8zxM1340JFNjZaF+ISWpr1Kt/jGo+ZTUzKkfw/pphEWbRCb+lmSM6k/TOgfYLvmbHkUQ0asIg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-remap-async-to-generator": "^7.22.20", + "@babel/plugin-syntax-async-generators": "^7.8.4" }, "engines": { "node": ">=6.9.0" @@ -2106,14 +1739,14 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", - "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.1.tgz", + "integrity": "sha512-AawPptitRXp1y0n4ilKcGbRYWfbbzFWz2NqNu7dacYDtFtz0CMjG64b3LQsb3KIgnf4/obcUL78hfaOS7iCUfw==", "dev": true, "dependencies": { - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-remap-async-to-generator": "^7.18.6" + "@babel/helper-module-imports": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-remap-async-to-generator": "^7.22.20" }, "engines": { "node": ">=6.9.0" @@ -2123,12 +1756,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", - "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.1.tgz", + "integrity": "sha512-TWWC18OShZutrv9C6mye1xwtam+uNi2bnTOCBUd5sZxyHOiWbU6ztSROofIMrK84uweEZC219POICK/sTYwfgg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2138,12 +1771,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.7.tgz", - "integrity": "sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.5.tgz", + "integrity": "sha512-sMfBc3OxghjC95BkYrYocHL3NaOplrcaunblzwXhGmlPwpmfsxr4vK+mBBt49r+S240vahmv+kUxkeKgs+haCw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.5" }, "engines": { "node": ">=6.9.0" @@ -2152,20 +1785,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.8.tgz", - "integrity": "sha512-VXy91c47uujj758ud9wx+OMgheXm4qJfyhj1P18YvlrQkNOSrwsteHk+EFS3OMGfhMhpZa0A+81eE7G4QC+3CA==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.8", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-replace-supers": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "globals": "^11.1.0" + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.1.tgz", + "integrity": "sha512-OMLCXi0NqvJfORTaPQBwqLXHhb93wkBKZ4aNwMl6WtehO7ar+cmp+89iPEQPqxAnxsOKTaMcs3POz3rKayJ72g==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2174,26 +1801,37 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-classes/node_modules/@babel/helper-annotate-as-pure": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", - "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.4.tgz", + "integrity": "sha512-B8q7Pz870Hz/q9UgP8InNpY01CSLDSCyqX7zcRuv3FcPl87A2G17lASroHWaCtbdIcbYzOZ7kWmXFKbijMSmFg==", "dev": true, "dependencies": { - "@babel/types": "^7.24.7" + "@babel/helper-create-class-features-plugin": "^7.24.4", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-class-static-block": "^7.14.5" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" } }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", - "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/template": "^7.24.7" + "node_modules/@babel/plugin-transform-classes": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.5.tgz", + "integrity": "sha512-gWkLP25DFj2dwe9Ck8uwMOpko4YsqyfZJrOmqqcegeDYEbp7rmn4U6UQZNj08UF6MaX39XenSpKRCvpDRBtZ7Q==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.24.5", + "@babel/helper-replace-supers": "^7.24.1", + "@babel/helper-split-export-declaration": "^7.24.5", + "globals": "^11.1.0" }, "engines": { "node": ">=6.9.0" @@ -2202,27 +1840,29 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-computed-properties/node_modules/@babel/template": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", - "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.1.tgz", + "integrity": "sha512-5pJGVIUfJpOS+pAqBQd+QMaTD2vCL/HcePooON6pDpHgRp4gNRmzyHTPIkXntwKsq3ayUFVfJaIKPw2pOkOcTw==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/template": "^7.24.0" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz", - "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.5.tgz", + "integrity": "sha512-SZuuLyfxvsm+Ah57I/i1HVjveBENYK9ue8MJ7qkc7ndoNjqquJiElzA7f5yaAXjyW2hKojosOTAQQRX50bPSVg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.24.5" }, "engines": { "node": ">=6.9.0" @@ -2232,13 +1872,13 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", - "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.1.tgz", + "integrity": "sha512-p7uUxgSoZwZ2lPNMzUkqCts3xlp8n+o05ikjy7gbtFJSt9gdU88jAmtfmOxHM14noQXBxfgzf2yRWECiNVhTCw==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2248,12 +1888,12 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", - "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.1.tgz", + "integrity": "sha512-msyzuUnvsjsaSaocV6L7ErfNsa5nDWL1XKNnDePLgmz+WdU4w/J8+AxBMrWfi9m4IxfL5sZQKUPQKDQeeAT6lA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2262,14 +1902,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", - "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.1.tgz", + "integrity": "sha512-av2gdSTyXcJVdI+8aFZsCAtR29xJt0S5tas+Ef8NvBNmD1a+N/3ecMLeMBgfcK+xzsjdLDT6oHt+DFPyeqUbDA==", "dev": true, "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" }, "engines": { "node": ">=6.9.0" @@ -2278,14 +1918,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", - "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.1.tgz", + "integrity": "sha512-U1yX13dVBSwS23DEAqU+Z/PkwE9/m7QQy8Y9/+Tdb8UWYaGNDYwTLi19wqIAiROr8sXVum9A/rtiH5H0boUcTw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2294,15 +1934,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.7.tgz", - "integrity": "sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==", + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.1.tgz", + "integrity": "sha512-Ft38m/KFOyzKw2UaJFkWG9QnHPG/Q/2SkOrRk4pNBPg5IPZ+dOxcmkK5IyuBcxiNPyyYowPGUReyBvrvZs7IlQ==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" }, "engines": { "node": ">=6.9.0" @@ -2311,13 +1950,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.7.tgz", - "integrity": "sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==", + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.1.tgz", + "integrity": "sha512-OxBdcnF04bpdQdR3i4giHZNZQn7cm8RQKcSwA17wAAqEELo1ZOwp5FFgeptWUQXFyT9kwHo10aqqauYkRZPCAg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -2326,13 +1966,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", - "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.1.tgz", + "integrity": "sha512-BXmDZpPlh7jwicKArQASrj8n22/w6iymRnvHYYd2zO30DbE277JO20/7yXJT3QxDPtiQiOxQBbZH4TpivNXIxA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2341,14 +1983,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", - "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.1.tgz", + "integrity": "sha512-U7RMFmRvoasscrIFy5xA4gIp8iWnWubnKkKuUGJjsuOH7GfbMkB+XZzeslx2kLdEGdOJDamEmCqOks6e8nv8DQ==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-json-strings": "^7.8.3" }, "engines": { "node": ">=6.9.0" @@ -2357,15 +1999,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz", - "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==", + "node_modules/@babel/plugin-transform-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.1.tgz", + "integrity": "sha512-zn9pwz8U7nCqOYIiBaOxoQOtYmMODXTJnkxG4AtX8fPmnCRYWBOHD0qcpwS9e2VDSp1zNJYpdnFMIKb8jmwu6g==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.24.8", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-simple-access": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2374,16 +2014,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.7.tgz", - "integrity": "sha512-GYQE0tW7YoaN13qFh3O1NCY4MPkUiAH3fiF7UcV/I3ajmDKEdG3l+UOcbAm4zUE3gnvUU+Eni7XrVKo9eO9auw==", + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.1.tgz", + "integrity": "sha512-OhN6J4Bpz+hIBqItTeWJujDOfNP+unqv/NJgyhlpSqgBTPm37KkMmZV6SYcOj+pnDbdcl1qRGV/ZiIjX9Iy34w==", "dev": true, "dependencies": { - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" }, "engines": { "node": ">=6.9.0" @@ -2392,14 +2030,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", - "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.1.tgz", + "integrity": "sha512-4ojai0KysTWXzHseJKa1XPNXKRbuUrhkOPY4rEGeR+7ChlJVKxFa3H3Bz+7tWaGKgJAXUWKOGmltN+u9B3+CVg==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2408,29 +2045,31 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", - "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.1.tgz", + "integrity": "sha512-lAxNHi4HVtjnHd5Rxg3D5t99Xm6H7b04hUS7EHIXcUl2EV4yl1gWdqZrNzXnSrHveL9qMdbODlLF55mvgjAfaQ==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", - "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.1.tgz", + "integrity": "sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-simple-access": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -2439,14 +2078,16 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", - "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.1.tgz", + "integrity": "sha512-mqQ3Zh9vFO1Tpmlt8QPnbwGHzNz3lpNEMxQb1kAemn/erstyqw1r9KeOlOfo3y6xAnFEcOv2tSyrXfmMk+/YZA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7" + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-identifier": "^7.22.20" }, "engines": { "node": ">=6.9.0" @@ -2455,15 +2096,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", - "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.1.tgz", + "integrity": "sha512-tuA3lpPj+5ITfcCluy6nWonSL7RvaG0AOTeAuvXqEKS34lnLzXpDb0dcP6K8jD0zWZFNDVly90AGFJPnm4fOYg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2472,28 +2112,29 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", - "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", - "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.1.tgz", + "integrity": "sha512-/rurytBM34hYy0HKZQyA0nHbQgQNFm4Q/BOc9Hflxi2X3twRof7NaE5W46j4kQitm7SvACVRXsa6N/tSZxvPug==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2502,14 +2143,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", - "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.1.tgz", + "integrity": "sha512-iQ+caew8wRrhCikO5DrUYx0mrmdhkaELgFa+7baMcVuhxIkN7oxt06CZ51D65ugIb1UWRQ8oQe+HXAVM6qHFjw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "regenerator-transform": "^0.15.2" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" }, "engines": { "node": ">=6.9.0" @@ -2518,13 +2159,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", - "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.1.tgz", + "integrity": "sha512-7GAsGlK4cNL2OExJH1DzmDeKnRv/LXq0eLUSvudrehVA5Rgg4bIrqEUW29FbKMBRT0ztSqisv7kjP+XIC4ZMNw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" }, "engines": { "node": ">=6.9.0" @@ -2533,18 +2175,16 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-runtime": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.6.tgz", - "integrity": "sha512-8uRHk9ZmRSnWqUgyae249EJZ94b0yAGLBIqzZzl+0iEdbno55Pmlt/32JZsHwXD9k/uZj18Aqqk35wBX4CBTXA==", + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.5.tgz", + "integrity": "sha512-7EauQHszLGM3ay7a161tTQH7fj+3vVM/gThlz5HpFtnygTxjrlvoeq7MPVA1Vy9Q555OB8SnAOsMkLShNkkrHA==", "dev": true, "dependencies": { - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "babel-plugin-polyfill-corejs2": "^0.3.1", - "babel-plugin-polyfill-corejs3": "^0.5.2", - "babel-plugin-polyfill-regenerator": "^0.3.1", - "semver": "^6.3.0" + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.24.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.24.5" }, "engines": { "node": ">=6.9.0" @@ -2553,22 +2193,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", - "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.1.tgz", + "integrity": "sha512-oKJqR3TeI5hSLRxudMjFQ9re9fBVUU0GICqM3J1mi8MqlhVr6hC/ZN4ttAyMuQR6EZZIY6h/exe5swqGNNIkWQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-replace-supers": "^7.24.1" }, "engines": { "node": ">=6.9.0" @@ -2577,14 +2209,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", - "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.1.tgz", + "integrity": "sha512-oBTH7oURV4Y+3EUrf6cWn1OHio3qG/PVwO5J03iSJmBg6m2EhKjkAu/xuaXaYwWW9miYtvbWv4LNf0AmR43LUA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" }, "engines": { "node": ">=6.9.0" @@ -2593,13 +2225,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", - "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.5.tgz", + "integrity": "sha512-xWCkmwKT+ihmA6l7SSTpk8e4qQl/274iNbSKRRS8mpqFR32ksy36+a+LWY8OXCCEefF8WFlnOHVsaDI2231wBg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, "engines": { "node": ">=6.9.0" @@ -2608,13 +2242,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", - "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.5.tgz", + "integrity": "sha512-9Co00MqZ2aoky+4j2jhofErthm6QVLKbpQrvz20c3CH9KQCLHyNB+t2ya4/UrRpQGR+Wrwjg9foopoeSdnHOkA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.5" }, "engines": { "node": ">=6.9.0" @@ -2623,13 +2257,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz", - "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==", + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.1.tgz", + "integrity": "sha512-tGvisebwBO5em4PaYNqt4fkw56K2VALsAbAakY0FjTYqJp7gfdrgr7YX76Or8/cpik0W6+tj3rZ0uHU9Oil4tw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2638,13 +2273,16 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", - "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.5.tgz", + "integrity": "sha512-JM4MHZqnWR04jPMujQDTBVRnqxpLLpx2tkn7iPn+Hmsc0Gnb79yvRWOkvqFOx3Z7P7VxiRIR22c4eGSNj87OBQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.24.5", + "@babel/helper-plugin-utils": "^7.24.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" }, "engines": { "node": ">=6.9.0" @@ -2653,14 +2291,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", - "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.1.tgz", + "integrity": "sha512-LetvD7CrHmEx0G442gOomRr66d7q8HzzGGr4PMHGr+5YIm6++Yke+jxj246rpvsbyhJwCLxcTn6zW1P1BSenqA==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2669,87 +2306,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-env": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.18.6.tgz", - "integrity": "sha512-WrthhuIIYKrEFAwttYzgRNQ5hULGmwTj+D6l7Zdfsv5M7IWV/OZbUfbeL++Qrzx1nVJwWROIFhCHRYQV4xbPNw==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.18.6", - "@babel/helper-compilation-targets": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.6", - "@babel/plugin-proposal-async-generator-functions": "^7.18.6", - "@babel/plugin-proposal-class-properties": "^7.18.6", - "@babel/plugin-proposal-class-static-block": "^7.18.6", - "@babel/plugin-proposal-dynamic-import": "^7.18.6", - "@babel/plugin-proposal-export-namespace-from": "^7.18.6", - "@babel/plugin-proposal-json-strings": "^7.18.6", - "@babel/plugin-proposal-logical-assignment-operators": "^7.18.6", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", - "@babel/plugin-proposal-numeric-separator": "^7.18.6", - "@babel/plugin-proposal-object-rest-spread": "^7.18.6", - "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", - "@babel/plugin-proposal-optional-chaining": "^7.18.6", - "@babel/plugin-proposal-private-methods": "^7.18.6", - "@babel/plugin-proposal-private-property-in-object": "^7.18.6", - "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.18.6", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.18.6", - "@babel/plugin-transform-async-to-generator": "^7.18.6", - "@babel/plugin-transform-block-scoped-functions": "^7.18.6", - "@babel/plugin-transform-block-scoping": "^7.18.6", - "@babel/plugin-transform-classes": "^7.18.6", - "@babel/plugin-transform-computed-properties": "^7.18.6", - "@babel/plugin-transform-destructuring": "^7.18.6", - "@babel/plugin-transform-dotall-regex": "^7.18.6", - "@babel/plugin-transform-duplicate-keys": "^7.18.6", - "@babel/plugin-transform-exponentiation-operator": "^7.18.6", - "@babel/plugin-transform-for-of": "^7.18.6", - "@babel/plugin-transform-function-name": "^7.18.6", - "@babel/plugin-transform-literals": "^7.18.6", - "@babel/plugin-transform-member-expression-literals": "^7.18.6", - "@babel/plugin-transform-modules-amd": "^7.18.6", - "@babel/plugin-transform-modules-commonjs": "^7.18.6", - "@babel/plugin-transform-modules-systemjs": "^7.18.6", - "@babel/plugin-transform-modules-umd": "^7.18.6", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.18.6", - "@babel/plugin-transform-new-target": "^7.18.6", - "@babel/plugin-transform-object-super": "^7.18.6", - "@babel/plugin-transform-parameters": "^7.18.6", - "@babel/plugin-transform-property-literals": "^7.18.6", - "@babel/plugin-transform-regenerator": "^7.18.6", - "@babel/plugin-transform-reserved-words": "^7.18.6", - "@babel/plugin-transform-shorthand-properties": "^7.18.6", - "@babel/plugin-transform-spread": "^7.18.6", - "@babel/plugin-transform-sticky-regex": "^7.18.6", - "@babel/plugin-transform-template-literals": "^7.18.6", - "@babel/plugin-transform-typeof-symbol": "^7.18.6", - "@babel/plugin-transform-unicode-escapes": "^7.18.6", - "@babel/plugin-transform-unicode-regex": "^7.18.6", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.18.6", - "babel-plugin-polyfill-corejs2": "^0.3.1", - "babel-plugin-polyfill-corejs3": "^0.5.2", - "babel-plugin-polyfill-regenerator": "^0.3.1", - "core-js-compat": "^3.22.1", - "semver": "^6.3.0" + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.1.tgz", + "integrity": "sha512-sJwZBCzIBE4t+5Q4IGLaaun5ExVMRY0lYwos/jNecjMrVCygCdph3IKv0tkP5Fc87e/1+bebAmEAGBfnRD+cnw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "regenerator-transform": "^0.15.2" }, "engines": { "node": ">=6.9.0" @@ -2758,7 +2322,42 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-env/node_modules/semver": { + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.1.tgz", + "integrity": "sha512-JAclqStUfIwKN15HrsQADFgeZt+wexNQ0uLhuqvqAUFoqPMjEcFCYZBhq0LUdz6dZK/mD+rErhW71fbx8RYElg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.24.3.tgz", + "integrity": "sha512-J0BuRPNlNqlMTRJ72eVptpt9VcInbxO6iP3jaxr+1NPhC0UkKL+6oeX6VXMEYdADnuqmMmsBspt4d5w8Y/TCbQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.24.3", + "@babel/helper-plugin-utils": "^7.24.0", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.1", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", @@ -2767,612 +2366,759 @@ "semver": "bin/semver.js" } }, - "node_modules/@babel/preset-modules": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6.tgz", - "integrity": "sha512-ID2yj6K/4lKfhuU3+EX4UvNbIt7eACFbHmNUjzA+ep+B5971CknnA/9DEWKbRokfbbtblxxxXFJJrH47UEAMVg==", + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.1.tgz", + "integrity": "sha512-LyjVB1nsJ6gTTUKRjRWx9C1s9hE7dLfP/knKdrfeH9UPtAGjYGgxIbFfx7xyLIEWs7Xe1Gnf8EWiUqfjLhInZA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", - "dev": true - }, - "node_modules/@babel/runtime": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.6.tgz", - "integrity": "sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ==", + "node_modules/@babel/plugin-transform-spread": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.1.tgz", + "integrity": "sha512-KjmcIM+fxgY+KxPVbjelJC6hrH1CgtPmTvdXAfn3/a9CnWGSTY7nH4zm5+cjmWJybdcPSsD0++QssDsjcpe47g==", "dev": true, "dependencies": { - "regenerator-runtime": "^0.13.4" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/template": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz", - "integrity": "sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==", + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.1.tgz", + "integrity": "sha512-9v0f1bRXgPVcPrngOQvLXeGNNVLc8UjMVfebo9ka0WF3/7+aVUHmaJVT3sa0XCzEFioPfPHZiOcYG9qOsH63cw==", + "dev": true, "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/traverse": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.8.tgz", - "integrity": "sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==", - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.8", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/parser": "^7.24.8", - "@babel/types": "^7.24.8", - "debug": "^4.3.1", - "globals": "^11.1.0" + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.1.tgz", + "integrity": "sha512-WRkhROsNzriarqECASCNu/nojeXCDTE/F2HmRgOzi7NGvyfYGq1NEjKBK3ckLfRgGc6/lPAqP0vDOSw3YtG34g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/traverse/node_modules/@babel/generator": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.8.tgz", - "integrity": "sha512-47DG+6F5SzOi0uEvK4wMShmn5yY0mVjVJoWTphdY2B4Rx9wHgjK7Yhtr0ru6nE+sn0v38mzrWOlah0p/YlHHOQ==", + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.5.tgz", + "integrity": "sha512-UTGnhYVZtTAjdwOTzT+sCyXmTn8AhaxOS/MjG9REclZ6ULHWF9KoCZur0HSGU7hk8PdBFKKbYe6+gqdXWz84Jg==", + "dev": true, "dependencies": { - "@babel/types": "^7.24.8", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" + "@babel/helper-plugin-utils": "^7.24.5" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/traverse/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.1.tgz", + "integrity": "sha512-RlkVIcWT4TLI96zM660S877E7beKlQw7Ig+wqkKBiWfj0zH5Q4h50q6er4wzZKRNSYpfo6ILJ+hrJAGSX2qcNw==", + "dev": true, "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/types": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.8.tgz", - "integrity": "sha512-SkSBEHwwJRU52QEVZBmMBnE5Ux2/6WU1grdYyOhpbCNxbmJrDuDCphBzKZSO3taf0zztp+qkWlymE5tVL5l0TA==", + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.1.tgz", + "integrity": "sha512-Ss4VvlfYV5huWApFsF8/Sq0oXnGO+jB+rijFEFugTd3cwSObUSnUi88djgR5528Csl0uKlrI331kRqe56Ov2Ng==", + "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.24.8", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@biesbjerg/ngx-translate-extract": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/@biesbjerg/ngx-translate-extract/-/ngx-translate-extract-7.0.4.tgz", - "integrity": "sha512-33hR94Fu26LK7Z+ImW2IdZiHfOcAzyIs1CdkUXg/536z2MqxBYqPoI9Ghsk6RTEfnsGa65wMgOcDXn7Ilhp8ew==", + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.1.tgz", + "integrity": "sha512-2A/94wgZgxfTsiLaQ2E36XAOdcZmGAaEEgVmxQWwZXWkGhvoHbaqXcKnU8zny4ycpu3vNqg0L/PcCiYtHtA13g==", "dev": true, "dependencies": { - "@phenomnomnominal/tsquery": "^4.1.1", - "boxen": "^5.0.1", - "colorette": "^1.2.2", - "flat": "^5.0.2", - "gettext-parser": "^4.0.4", - "glob": "^7.1.6", - "mkdirp": "^1.0.4", - "path": "^0.12.7", - "terminal-link": "^2.1.1", - "yargs": "^16.2.0" - }, - "bin": { - "ngx-translate-extract": "bin/cli.js" + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { - "node": ">=11.15.0" + "node": ">=6.9.0" }, "peerDependencies": { - "@angular/compiler": ">=8.0.0", - "typescript": ">=3.0.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@biesbjerg/ngx-translate-extract-marker": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@biesbjerg/ngx-translate-extract-marker/-/ngx-translate-extract-marker-1.0.0.tgz", - "integrity": "sha512-GlCBQKmFE+b+qfIO0aGvuRc4LJVSfK27K2QQFXZLP55/w28iiq/q2CnBS8ya+4l+hapm7U3QPtFoZu9lmbUuew==", + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.1.tgz", + "integrity": "sha512-fqj4WuzzS+ukpgerpAoOnMfQXwUHFxXUZUE84oL2Kao2N8uSlvcpnAidKASgsNgzZHBsHWvcm8s9FPWUhAb8fA==", "dev": true, "dependencies": { - "tslib": "^1.9.0" + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@biesbjerg/ngx-translate-extract-marker/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "node_modules/@babel/preset-env": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.5.tgz", + "integrity": "sha512-UGK2ifKtcC8i5AI4cH+sbLLuLc2ktYSFJgBAXorKAsHUZmrQ1q6aQ6i3BvU24wWs2AAKqQB6kq3N9V9Gw1HiMQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.24.4", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.24.5", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.5", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.1", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.24.1", + "@babel/plugin-syntax-import-attributes": "^7.24.1", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.24.1", + "@babel/plugin-transform-async-generator-functions": "^7.24.3", + "@babel/plugin-transform-async-to-generator": "^7.24.1", + "@babel/plugin-transform-block-scoped-functions": "^7.24.1", + "@babel/plugin-transform-block-scoping": "^7.24.5", + "@babel/plugin-transform-class-properties": "^7.24.1", + "@babel/plugin-transform-class-static-block": "^7.24.4", + "@babel/plugin-transform-classes": "^7.24.5", + "@babel/plugin-transform-computed-properties": "^7.24.1", + "@babel/plugin-transform-destructuring": "^7.24.5", + "@babel/plugin-transform-dotall-regex": "^7.24.1", + "@babel/plugin-transform-duplicate-keys": "^7.24.1", + "@babel/plugin-transform-dynamic-import": "^7.24.1", + "@babel/plugin-transform-exponentiation-operator": "^7.24.1", + "@babel/plugin-transform-export-namespace-from": "^7.24.1", + "@babel/plugin-transform-for-of": "^7.24.1", + "@babel/plugin-transform-function-name": "^7.24.1", + "@babel/plugin-transform-json-strings": "^7.24.1", + "@babel/plugin-transform-literals": "^7.24.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.1", + "@babel/plugin-transform-member-expression-literals": "^7.24.1", + "@babel/plugin-transform-modules-amd": "^7.24.1", + "@babel/plugin-transform-modules-commonjs": "^7.24.1", + "@babel/plugin-transform-modules-systemjs": "^7.24.1", + "@babel/plugin-transform-modules-umd": "^7.24.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.24.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.1", + "@babel/plugin-transform-numeric-separator": "^7.24.1", + "@babel/plugin-transform-object-rest-spread": "^7.24.5", + "@babel/plugin-transform-object-super": "^7.24.1", + "@babel/plugin-transform-optional-catch-binding": "^7.24.1", + "@babel/plugin-transform-optional-chaining": "^7.24.5", + "@babel/plugin-transform-parameters": "^7.24.5", + "@babel/plugin-transform-private-methods": "^7.24.1", + "@babel/plugin-transform-private-property-in-object": "^7.24.5", + "@babel/plugin-transform-property-literals": "^7.24.1", + "@babel/plugin-transform-regenerator": "^7.24.1", + "@babel/plugin-transform-reserved-words": "^7.24.1", + "@babel/plugin-transform-shorthand-properties": "^7.24.1", + "@babel/plugin-transform-spread": "^7.24.1", + "@babel/plugin-transform-sticky-regex": "^7.24.1", + "@babel/plugin-transform-template-literals": "^7.24.1", + "@babel/plugin-transform-typeof-symbol": "^7.24.5", + "@babel/plugin-transform-unicode-escapes": "^7.24.1", + "@babel/plugin-transform-unicode-property-regex": "^7.24.1", + "@babel/plugin-transform-unicode-regex": "^7.24.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.24.1", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.4", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/@biesbjerg/ngx-translate-extract/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@biesbjerg/ngx-translate-extract/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", "dev": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@biesbjerg/ngx-translate-extract/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "dev": true + }, + "node_modules/@babel/runtime": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz", + "integrity": "sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "regenerator-runtime": "^0.14.0" }, "engines": { - "node": "*" + "node": ">=6.9.0" } }, - "node_modules/@biesbjerg/ngx-translate-extract/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "node_modules/@babel/template": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", "dev": true, "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" }, "engines": { - "node": ">=10" + "node": ">=6.9.0" } }, - "node_modules/@biesbjerg/ngx-translate-extract/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "node_modules/@babel/traverse": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.5.tgz", + "integrity": "sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.24.5", + "@babel/parser": "^7.24.5", + "@babel/types": "^7.24.5", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz", + "integrity": "sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==", "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.24.1", + "@babel/helper-validator-identifier": "^7.24.5", + "to-fast-properties": "^2.0.0" + }, "engines": { - "node": ">=10" + "node": ">=6.9.0" } }, "node_modules/@braintree/sanitize-url": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.4.tgz", - "integrity": "sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==" + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.0.tgz", + "integrity": "sha512-o+UlMLt49RvtCASlOMW0AkHnabN9wR9rwCCherxO0yG4Npy34GkvrAqdXQvrhNs+jh+gkK8gB8Lf05qL/O7KWg==", + "optional": true + }, + "node_modules/@chevrotain/cst-dts-gen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz", + "integrity": "sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==", + "optional": true, + "dependencies": { + "@chevrotain/gast": "11.0.3", + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/@chevrotain/gast": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.0.3.tgz", + "integrity": "sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==", + "optional": true, + "dependencies": { + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/@chevrotain/regexp-to-ast": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz", + "integrity": "sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==", + "optional": true + }, + "node_modules/@chevrotain/types": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.0.3.tgz", + "integrity": "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==", + "optional": true + }, + "node_modules/@chevrotain/utils": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.0.3.tgz", + "integrity": "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==", + "optional": true }, "node_modules/@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", "dev": true, - "optional": true, "engines": { "node": ">=0.1.90" } }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "node": ">=10.0.0" } }, - "node_modules/@csstools/postcss-cascade-layers": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz", - "integrity": "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==", + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.3.tgz", + "integrity": "sha512-yTgnwQpFVYfvvo4SvRFB0SwrW8YjOxEoT7wfMT7Ol5v7v5LDNvSGo67aExmxOb87nQNeWPVvaGBNfQ7BXcrZ9w==", + "cpu": [ + "ppc64" + ], "dev": true, - "dependencies": { - "@csstools/selector-specificity": "^2.0.2", - "postcss-selector-parser": "^6.0.10" - }, + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">=12" } }, - "node_modules/@csstools/postcss-color-function": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-1.1.1.tgz", - "integrity": "sha512-Bc0f62WmHdtRDjf5f3e2STwRAl89N2CLb+9iAwzrv4L2hncrbDwnQD9PCq0gtAt7pOI2leIV08HIBUd4jxD8cw==", + "node_modules/@esbuild/android-arm": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.3.tgz", + "integrity": "sha512-bviJOLMgurLJtF1/mAoJLxDZDL6oU5/ztMHnJQRejbJrSc9FFu0QoUoFhvi6qSKJEw9y5oGyvr9fuDtzJ30rNQ==", + "cpu": [ + "arm" + ], "dev": true, - "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">=12" } }, - "node_modules/@csstools/postcss-font-format-keywords": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-1.0.1.tgz", - "integrity": "sha512-ZgrlzuUAjXIOc2JueK0X5sZDjCtgimVp/O5CEqTcs5ShWBa6smhWYbS0x5cVc/+rycTDbjjzoP0KTDnUneZGOg==", + "node_modules/@esbuild/android-arm64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.3.tgz", + "integrity": "sha512-c+ty9necz3zB1Y+d/N+mC6KVVkGUUOcm4ZmT5i/Fk5arOaY3i6CA3P5wo/7+XzV8cb4GrI/Zjp8NuOQ9Lfsosw==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">=12" } }, - "node_modules/@csstools/postcss-hwb-function": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-1.0.2.tgz", - "integrity": "sha512-YHdEru4o3Rsbjmu6vHy4UKOXZD+Rn2zmkAmLRfPet6+Jz4Ojw8cbWxe1n42VaXQhD3CQUXXTooIy8OkVbUcL+w==", + "node_modules/@esbuild/android-x64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.3.tgz", + "integrity": "sha512-JReHfYCRK3FVX4Ra+y5EBH1b9e16TV2OxrPAvzMsGeES0X2Ndm9ImQRI4Ket757vhc5XBOuGperw63upesclRw==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">=12" } }, - "node_modules/@csstools/postcss-ic-unit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-1.0.1.tgz", - "integrity": "sha512-Ot1rcwRAaRHNKC9tAqoqNZhjdYBzKk1POgWfhN4uCOE47ebGcLRqXjKkApVDpjifL6u2/55ekkpnFcp+s/OZUw==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.3.tgz", + "integrity": "sha512-U3fuQ0xNiAkXOmQ6w5dKpEvXQRSpHOnbw7gEfHCRXPeTKW9sBzVck6C5Yneb8LfJm0l6le4NQfkNPnWMSlTFUQ==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">=12" } }, - "node_modules/@csstools/postcss-is-pseudo-class": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-2.0.7.tgz", - "integrity": "sha512-7JPeVVZHd+jxYdULl87lvjgvWldYu+Bc62s9vD/ED6/QTGjy0jy0US/f6BG53sVMTBJ1lzKZFpYmofBN9eaRiA==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.3.tgz", + "integrity": "sha512-3m1CEB7F07s19wmaMNI2KANLcnaqryJxO1fXHUV5j1rWn+wMxdUYoPyO2TnAbfRZdi7ADRwJClmOwgT13qlP3Q==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "@csstools/selector-specificity": "^2.0.0", - "postcss-selector-parser": "^6.0.10" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">=12" } }, - "node_modules/@csstools/postcss-normalize-display-values": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-1.0.1.tgz", - "integrity": "sha512-jcOanIbv55OFKQ3sYeFD/T0Ti7AMXc9nM1hZWu8m/2722gOTxFg7xYu4RDLJLeZmPUVQlGzo4jhzvTUq3x4ZUw==", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.3.tgz", + "integrity": "sha512-fsNAAl5pU6wmKHq91cHWQT0Fz0vtyE1JauMzKotrwqIKAswwP5cpHUCxZNSTuA/JlqtScq20/5KZ+TxQdovU/g==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">=12" } }, - "node_modules/@csstools/postcss-oklab-function": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-1.1.1.tgz", - "integrity": "sha512-nJpJgsdA3dA9y5pgyb/UfEzE7W5Ka7u0CX0/HIMVBNWzWemdcTH3XwANECU6anWv/ao4vVNLTMxhiPNZsTK6iA==", + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.3.tgz", + "integrity": "sha512-tci+UJ4zP5EGF4rp8XlZIdq1q1a/1h9XuronfxTMCNBslpCtmk97Q/5qqy1Mu4zIc0yswN/yP/BLX+NTUC1bXA==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">=12" } }, - "node_modules/@csstools/postcss-progressive-custom-properties": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz", - "integrity": "sha512-ASA9W1aIy5ygskZYuWams4BzafD12ULvSypmaLJT2jvQ8G0M3I8PRQhC0h7mG0Z3LI05+agZjqSR9+K9yaQQjA==", + "node_modules/@esbuild/linux-arm": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.3.tgz", + "integrity": "sha512-f6kz2QpSuyHHg01cDawj0vkyMwuIvN62UAguQfnNVzbge2uWLhA7TCXOn83DT0ZvyJmBI943MItgTovUob36SQ==", + "cpu": [ + "arm" + ], "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" + "node": ">=12" } }, - "node_modules/@csstools/postcss-stepped-value-functions": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-1.0.1.tgz", - "integrity": "sha512-dz0LNoo3ijpTOQqEJLY8nyaapl6umbmDcgj4AD0lgVQ572b2eqA1iGZYTTWhrcrHztWDDRAX2DGYyw2VBjvCvQ==", + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.3.tgz", + "integrity": "sha512-vvG6R5g5ieB4eCJBQevyDMb31LMHthLpXTc2IGkFnPWS/GzIFDnaYFp558O+XybTmYrVjxnryru7QRleJvmZ6Q==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">=12" } }, - "node_modules/@csstools/postcss-trigonometric-functions": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-1.0.2.tgz", - "integrity": "sha512-woKaLO///4bb+zZC2s80l+7cm07M7268MsyG3M0ActXXEFi6SuhvriQYcb58iiKGbjwwIU7n45iRLEHypB47Og==", + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.3.tgz", + "integrity": "sha512-HjCWhH7K96Na+66TacDLJmOI9R8iDWDDiqe17C7znGvvE4sW1ECt9ly0AJ3dJH62jHyVqW9xpxZEU1jKdt+29A==", + "cpu": [ + "ia32" + ], "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">=12" } }, - "node_modules/@csstools/postcss-unset-value": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.2.tgz", - "integrity": "sha512-c8J4roPBILnelAsdLr4XOAR/GsTm0GJi4XpcfvoWk3U6KiTCqiFYc63KhRMQQX35jYMp4Ao8Ij9+IZRgMfJp1g==", + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.3.tgz", + "integrity": "sha512-BGpimEccmHBZRcAhdlRIxMp7x9PyJxUtj7apL2IuoG9VxvU/l/v1z015nFs7Si7tXUwEsvjc1rOJdZCn4QTU+Q==", + "cpu": [ + "loong64" + ], "dev": true, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">=12" } }, - "node_modules/@csstools/selector-specificity": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz", - "integrity": "sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==", + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.3.tgz", + "integrity": "sha512-5rMOWkp7FQGtAH3QJddP4w3s47iT20hwftqdm7b+loe95o8JU8ro3qZbhgMRy0VuFU0DizymF1pBKkn3YHWtsw==", + "cpu": [ + "mips64el" + ], "dev": true, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^14 || ^16 || >=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss-selector-parser": "^6.0.10" - } - }, - "node_modules/@cypress/request": { - "version": "2.88.12", - "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.12.tgz", - "integrity": "sha512-tOn+0mDZxASFM+cuAP9szGUGPI1HwWVSvdzm7V4cCsPdFTx6qMj29CwaQmRAMIEhORIUBFBsYROYJcveK4uOjA==", - "dev": true, - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "http-signature": "~1.3.6", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "performance-now": "^2.1.0", - "qs": "~6.10.3", - "safe-buffer": "^5.1.2", - "tough-cookie": "^4.1.3", - "tunnel-agent": "^0.6.0", - "uuid": "^8.3.2" - }, - "engines": { - "node": ">= 6" + "node": ">=12" } }, - "node_modules/@cypress/schematic": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@cypress/schematic/-/schematic-2.5.2.tgz", - "integrity": "sha512-H+V3ZP3KQVOs6b49N66jioXa+rkLzszVi+Bl3jiroVTURUNMOpSa4BOrt10Pn8F57TO0Bamhch2WOk/e9cq98w==", + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.3.tgz", + "integrity": "sha512-h0zj1ldel89V5sjPLo5H1SyMzp4VrgN1tPkN29TmjvO1/r0MuMRwJxL8QY05SmfsZRs6TF0c/IDH3u7XYYmbAg==", + "cpu": [ + "ppc64" + ], "dev": true, - "dependencies": { - "jsonc-parser": "^3.0.0", - "rxjs": "~6.6.0" - }, - "peerDependencies": { - "@angular/cli": ">=14", - "@angular/core": ">=14" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@cypress/schematic/node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.3.tgz", + "integrity": "sha512-dkAKcTsTJ+CRX6bnO17qDJbLoW37npd5gSNtSzjYQr0svghLJYGYB0NF1SNcU1vDcjXLYS5pO4qOW4YbFama4A==", + "cpu": [ + "riscv64" + ], "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "npm": ">=2.0.0" + "node": ">=12" } }, - "node_modules/@cypress/schematic/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.3.tgz", + "integrity": "sha512-vnD1YUkovEdnZWEuMmy2X2JmzsHQqPpZElXx6dxENcIwTu+Cu5ERax6+Ke1QsE814Zf3c6rxCfwQdCTQ7tPuXA==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } }, - "node_modules/@cypress/xvfb": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", - "integrity": "sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==", + "node_modules/@esbuild/linux-x64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.3.tgz", + "integrity": "sha512-IOXOIm9WaK7plL2gMhsWJd+l2bfrhfilv0uPTptoRoSb2p09RghhQQp9YY6ZJhk/kqmeRt6siRdMSLLwzuT0KQ==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "debug": "^3.1.0", - "lodash.once": "^4.1.1" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@cypress/xvfb/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.3.tgz", + "integrity": "sha512-uTgCwsvQ5+vCQnqM//EfDSuomo2LhdWhFPS8VL8xKf+PKTCrcT/2kPPoWMTs22aB63MLdGMJiE3f1PHvCDmUOw==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "ms": "^2.1.1" + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.3.tgz", + "integrity": "sha512-vNAkR17Ub2MgEud2Wag/OE4HTSI6zlb291UYzHez/psiKarp0J8PKGDnAhMBcHFoOHMXHfExzmjMojJNbAStrQ==", + "cpu": [ + "x64" + ], "dev": true, + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=10.0.0" + "node": ">=12" } }, - "node_modules/@es-joy/jsdoccomment": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.46.0.tgz", - "integrity": "sha512-C3Axuq1xd/9VqFZpW4YAzOx5O9q/LP46uIQy/iNDpHG3fmPa6TBtvfglMCs3RBiBxAIi0Go97r8+jvTt55XMyQ==", + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.3.tgz", + "integrity": "sha512-W8H9jlGiSBomkgmouaRoTXo49j4w4Kfbl6I1bIdO/vT0+0u4f20ko3ELzV3hPI6XV6JNBVX+8BC+ajHkvffIJA==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "comment-parser": "1.4.1", - "esquery": "^1.6.0", - "jsdoc-type-pratt-parser": "~4.0.0" - }, + "optional": true, + "os": [ + "sunos" + ], "engines": { - "node": ">=16" + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.3.tgz", + "integrity": "sha512-EjEomwyLSCg8Ag3LDILIqYCZAq/y3diJ04PnqGRgq8/4O3VNlXyMd54j/saShaN4h5o5mivOjAzmU6C3X4v0xw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.3.tgz", + "integrity": "sha512-WGiE/GgbsEwR33++5rzjiYsKyHywE8QSZPF7Rfx9EBfK3Qn3xyR6IjyCr5Uk38Kg8fG4/2phN7sXp4NPWd3fcw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.3.tgz", + "integrity": "sha512-xRxC0jaJWDLYvcUvjQmHCJSfMrgmUuvsoXgDeU/wTorQ1ngDdUBuFtgY3W1Pc5sprGAvZBtWdJX7RPg/iZZUqA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" } }, "node_modules/@eslint-community/eslint-utils": { @@ -3391,24 +3137,69 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", - "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", + "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/config-array": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", + "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "dev": true, + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/core": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.6.0.tgz", + "integrity": "sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -3416,7 +3207,7 @@ "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -3455,15 +3246,12 @@ } }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -3500,129 +3288,55 @@ } }, "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "version": "9.12.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.12.0.tgz", + "integrity": "sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@fastify/accept-negotiator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@fastify/accept-negotiator/-/accept-negotiator-1.1.0.tgz", - "integrity": "sha512-OIHZrb2ImZ7XG85HXOONLcJWGosv7sIvM2ifAPQVhg9Lv7qdmMBNVaai4QTdyuaqbKM5eO6sLSQOYI7wEQeCJQ==", - "engines": { - "node": ">=14" - } - }, - "node_modules/@fastify/send": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@fastify/send/-/send-2.1.0.tgz", - "integrity": "sha512-yNYiY6sDkexoJR0D8IDy3aRP3+L4wdqCpvx5WP+VtEU58sn7USmKynBzDQex5X42Zzvw2gNzzYgP90UfWShLFA==", - "dependencies": { - "@lukeed/ms": "^2.0.1", - "escape-html": "~1.0.3", - "fast-decode-uri-component": "^1.0.1", - "http-errors": "2.0.0", - "mime": "^3.0.0" - } - }, - "node_modules/@fastify/static": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/@fastify/static/-/static-7.0.4.tgz", - "integrity": "sha512-p2uKtaf8BMOZWLs6wu+Ihg7bWNBdjNgCwDza4MJtTqg+5ovKmcbgbR9Xs5/smZ1YISfzKOCNYmZV8LaCj+eJ1Q==", - "dependencies": { - "@fastify/accept-negotiator": "^1.0.0", - "@fastify/send": "^2.0.0", - "content-disposition": "^0.5.3", - "fastify-plugin": "^4.0.0", - "fastq": "^1.17.0", - "glob": "^10.3.4" - } - }, - "node_modules/@fastify/static/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@fastify/static/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@fastify/static/node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@gar/promisify": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "dev": true - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "deprecated": "Use @eslint/config-array instead", + "node_modules/@eslint/plugin-kit": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz", + "integrity": "sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "levn": "^0.4.1" }, "engines": { - "node": ">=10.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/@humanfs/core": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.0.tgz", + "integrity": "sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw==", "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "engines": { + "node": ">=18.18.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@humanfs/node": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.5.tgz", + "integrity": "sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "@humanfs/core": "^0.19.0", + "@humanwhocodes/retry": "^0.3.0" }, "engines": { - "node": "*" + "node": ">=18.18.0" } }, "node_modules/@humanwhocodes/module-importer": { @@ -3638,12 +3352,48 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true + "node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "optional": true + }, + "node_modules/@iconify/utils": { + "version": "2.1.33", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-2.1.33.tgz", + "integrity": "sha512-jP9h6v/g0BIZx0p7XGJJVtkVnydtbgTgt9mVNcGDYwaa7UhdHdI9dvoq+gKj9sijMSJKxUPEG2JyjsgXjxL7Kw==", + "optional": true, + "dependencies": { + "@antfu/install-pkg": "^0.4.0", + "@antfu/utils": "^0.7.10", + "@iconify/types": "^2.0.0", + "debug": "^4.3.6", + "kolorist": "^1.8.0", + "local-pkg": "^0.5.0", + "mlly": "^1.7.1" + } + }, + "node_modules/@inquirer/figures": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.2.tgz", + "integrity": "sha512-4F1MBwVr3c/m4bAUef6LgkvBfSjzwH+OfldgHqcuacWwSUetFebM2wi58WfG9uk1rR98U6GwLed4asLJbwdV5w==", + "dev": true, + "engines": { + "node": ">=18" + } }, "node_modules/@isaacs/cliui": { "version": "8.0.2", @@ -3759,898 +3509,1097 @@ "node": ">=8" } }, - "node_modules/@jest/console": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.3.tgz", - "integrity": "sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==", + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, "dependencies": { - "@jest/types": "^28.1.3", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3", - "slash": "^3.0.0" + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": ">=6.0.0" } }, - "node_modules/@jest/console/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=6.0.0" } }, - "node_modules/@jest/console/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=6.0.0" } }, - "node_modules/@jest/console/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", "dev": true, "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" } }, - "node_modules/@jest/console/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", "dev": true }, - "node_modules/@jest/console/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@jest/core": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-28.1.3.tgz", - "integrity": "sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA==", + "node_modules/@jsonjoy.com/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", "dev": true, - "dependencies": { - "@jest/console": "^28.1.3", - "@jest/reporters": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^28.1.3", - "jest-config": "^28.1.3", - "jest-haste-map": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.1.3", - "jest-resolve-dependencies": "^28.1.3", - "jest-runner": "^28.1.3", - "jest-runtime": "^28.1.3", - "jest-snapshot": "^28.1.3", - "jest-util": "^28.1.3", - "jest-validate": "^28.1.3", - "jest-watcher": "^28.1.3", - "micromatch": "^4.0.4", - "pretty-format": "^28.1.3", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": ">=10.0" }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "peerDependencies": { + "tslib": "2" } }, - "node_modules/@jest/core/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@jsonjoy.com/json-pack": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.0.4.tgz", + "integrity": "sha512-aOcSN4MeAtFROysrbqG137b7gaDDSmVrl5mpo6sT/w+kcXpWnzhMjmY/Fh/sDx26NBxyIE7MB1seqLeCAzy9Sg==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "@jsonjoy.com/base64": "^1.1.1", + "@jsonjoy.com/util": "^1.1.2", + "hyperdyperid": "^1.2.0", + "thingies": "^1.20.0" }, "engines": { - "node": ">=8" + "node": ">=10.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, - "node_modules/@jest/core/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@jsonjoy.com/util": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.1.3.tgz", + "integrity": "sha512-g//kkF4kOwUjemValCtOc/xiYzmwMRmWq3Bn+YnzOzuZLHq2PpMOxxIayN3cKbo7Ko2Np65t6D9H81IvXbXhqg==", "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=10" + "node": ">=10.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, - "node_modules/@jest/core/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true + }, + "node_modules/@ljharb/through": { + "version": "2.3.13", + "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.13.tgz", + "integrity": "sha512-/gKJun8NNiWGZJkGzI/Ragc53cOdcLNdzjLaIa+GEjguQs0ulsurx8WN0jijdK9yPqDvziX995sMRLyLt1uZMQ==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "call-bind": "^1.0.7" }, "engines": { - "node": ">=7.0.0" + "node": ">= 0.4" } }, - "node_modules/@jest/core/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "node_modules/@lmdb/lmdb-darwin-arm64": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.0.8.tgz", + "integrity": "sha512-+lFwFvU+zQ9zVIFETNtmW++syh3Ps5JS8MPQ8zOYtQZoU+dTR8ivWHTaE2QVk1JG2payGDLUAvpndLAjGMdeeA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@jest/core/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/@lmdb/lmdb-darwin-x64": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.0.8.tgz", + "integrity": "sha512-T98rfsgfdQMS5/mqdsPb6oHSJ+iBYNa+PQDLtXLh6rzTEBsYP9x2uXxIj6VS4qXVDWXVi8rv85NCOG+UBOsHXQ==", + "cpu": [ + "x64" + ], "dev": true, - "engines": { - "node": ">=8" - } + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@jest/core/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@lmdb/lmdb-linux-arm": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.0.8.tgz", + "integrity": "sha512-gVNCi3bYWatdPMeFpFjuZl6bzVL55FkeZU3sPeU+NsMRXC+Zl3qOx3M6cM4OMlJWbhHjYjf2b8q83K0mczaiWQ==", + "cpu": [ + "arm" + ], "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@jest/environment": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.3.tgz", - "integrity": "sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA==", + "node_modules/@lmdb/lmdb-linux-arm64": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.0.8.tgz", + "integrity": "sha512-uEBGCQIChsixpykL0pjCxfF64btv64vzsb1NoM5u0qvabKvKEvErhXGoqovyldDu9u1T/fswD8Kf6ih0vJEvDQ==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "@jest/fake-timers": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/node": "*", - "jest-mock": "^28.1.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@jest/expect": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.1.3.tgz", - "integrity": "sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw==", + "node_modules/@lmdb/lmdb-linux-x64": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.0.8.tgz", + "integrity": "sha512-6v0B4sa9ulNezmDZtVpLjNHmA0qZzUl3001YJ2RF0naxsuv/Jq/xEwNYpOzfcdizHfpCE0oBkWzk/r+Slr+0zw==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "expect": "^28.1.3", - "jest-snapshot": "^28.1.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@jest/expect-utils": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", - "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", + "node_modules/@lmdb/lmdb-win32-x64": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.0.8.tgz", + "integrity": "sha512-lDLGRIMqdwYD39vinwNqqZUxCdL2m2iIdn+0HyQgIHEiT0g5rIAlzaMKzoGWon5NQumfxXFk9y0DarttkR7C1w==", + "cpu": [ + "x64" + ], "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@material/animation": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-1GSJaPKef+7HRuV+HusVZHps64cmZuOItDbt40tjJVaikcaZvwmHlcTxRIqzcRoCdt5ZKHh3NoO7GB9Khg4Jnw==", "dependencies": { - "jest-get-type": "^28.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "tslib": "^2.1.0" } }, - "node_modules/@jest/fake-timers": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.3.tgz", - "integrity": "sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw==", - "dev": true, + "node_modules/@material/auto-init": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/auto-init/-/auto-init-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-t7ZGpRJ3ec0QDUO0nJu/SMgLW7qcuG2KqIsEYD1Ej8qhI2xpdR2ydSDQOkVEitXmKoGol1oq4nYSBjTlB65GqA==", "dependencies": { - "@jest/types": "^28.1.3", - "@sinonjs/fake-timers": "^9.1.2", - "@types/node": "*", - "jest-message-util": "^28.1.3", - "jest-mock": "^28.1.3", - "jest-util": "^28.1.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "@material/base": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@jest/globals": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.1.3.tgz", - "integrity": "sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA==", - "dev": true, - "dependencies": { - "@jest/environment": "^28.1.3", - "@jest/expect": "^28.1.3", - "@jest/types": "^28.1.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node_modules/@material/banner": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/banner/-/banner-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-g9wBUZzYBizyBcBQXTIafnRUUPi7efU9gPJfzeGgkynXiccP/vh5XMmH+PBxl5v+4MlP/d4cZ2NUYoAN7UTqSA==", + "dependencies": { + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/button": "15.0.0-canary.7f224ddd4.0", + "@material/dom": "15.0.0-canary.7f224ddd4.0", + "@material/elevation": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/ripple": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/shape": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/tokens": "15.0.0-canary.7f224ddd4.0", + "@material/typography": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@jest/reporters": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.1.3.tgz", - "integrity": "sha512-JuAy7wkxQZVNU/V6g9xKzCGC5LVXx9FDcABKsSXp5MiKPEE2144a/vXTEDoyzjUpZKfVwp08Wqg5A4WfTMAzjg==", - "dev": true, + "node_modules/@material/base": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-I9KQOKXpLfJkP8MqZyr8wZIzdPHrwPjFvGd9zSK91/vPyE4hzHRJc/0njsh9g8Lm9PRYLbifXX+719uTbHxx+A==", "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", - "@jridgewell/trace-mapping": "^0.3.13", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3", - "jest-worker": "^28.1.3", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "tslib": "^2.1.0" } }, - "node_modules/@jest/reporters/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node_modules/@material/button": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/button/-/button-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-BHB7iyHgRVH+JF16+iscR+Qaic+p7LU1FOLgP8KucRlpF9tTwIxQA6mJwGRi5gUtcG+vyCmzVS+hIQ6DqT/7BA==", + "dependencies": { + "@material/density": "15.0.0-canary.7f224ddd4.0", + "@material/dom": "15.0.0-canary.7f224ddd4.0", + "@material/elevation": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/focus-ring": "15.0.0-canary.7f224ddd4.0", + "@material/ripple": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/shape": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/tokens": "15.0.0-canary.7f224ddd4.0", + "@material/touch-target": "15.0.0-canary.7f224ddd4.0", + "@material/typography": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@jest/reporters/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, + "node_modules/@material/card": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/card/-/card-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-kt7y9/IWOtJTr3Z/AoWJT3ZLN7CLlzXhx2udCLP9ootZU2bfGK0lzNwmo80bv/pJfrY9ihQKCtuGTtNxUy+vIw==", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@material/dom": "15.0.0-canary.7f224ddd4.0", + "@material/elevation": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/ripple": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/shape": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/tokens": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@jest/reporters/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node_modules/@material/checkbox": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/checkbox/-/checkbox-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-rURcrL5O1u6hzWR+dNgiQ/n89vk6tdmdP3mZgnxJx61q4I/k1yijKqNJSLrkXH7Rto3bM5NRKMOlgvMvVd7UMQ==", + "dependencies": { + "@material/animation": "15.0.0-canary.7f224ddd4.0", + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/density": "15.0.0-canary.7f224ddd4.0", + "@material/dom": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/focus-ring": "15.0.0-canary.7f224ddd4.0", + "@material/ripple": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/touch-target": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@jest/reporters/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "node_modules/@material/chips": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/chips/-/chips-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-AYAivV3GSk/T/nRIpH27sOHFPaSMrE3L0WYbnb5Wa93FgY8a0fbsFYtSH2QmtwnzXveg+B1zGTt7/xIIcynKdQ==", + "dependencies": { + "@material/animation": "15.0.0-canary.7f224ddd4.0", + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/checkbox": "15.0.0-canary.7f224ddd4.0", + "@material/density": "15.0.0-canary.7f224ddd4.0", + "@material/dom": "15.0.0-canary.7f224ddd4.0", + "@material/elevation": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/focus-ring": "15.0.0-canary.7f224ddd4.0", + "@material/ripple": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/shape": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/tokens": "15.0.0-canary.7f224ddd4.0", + "@material/touch-target": "15.0.0-canary.7f224ddd4.0", + "@material/typography": "15.0.0-canary.7f224ddd4.0", + "safevalues": "^0.3.4", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/circular-progress": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/circular-progress/-/circular-progress-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-DJrqCKb+LuGtjNvKl8XigvyK02y36GRkfhMUYTcJEi3PrOE00bwXtyj7ilhzEVshQiXg6AHGWXtf5UqwNrx3Ow==", "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "@material/animation": "15.0.0-canary.7f224ddd4.0", + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/dom": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/progress-indicator": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@jest/reporters/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "node_modules/@material/data-table": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/data-table/-/data-table-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-/2WZsuBIq9z9RWYF5Jo6b7P6u0fwit+29/mN7rmAZ6akqUR54nXyNfoSNiyydMkzPlZZsep5KrSHododDhBZbA==", + "dependencies": { + "@material/animation": "15.0.0-canary.7f224ddd4.0", + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/checkbox": "15.0.0-canary.7f224ddd4.0", + "@material/density": "15.0.0-canary.7f224ddd4.0", + "@material/dom": "15.0.0-canary.7f224ddd4.0", + "@material/elevation": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/icon-button": "15.0.0-canary.7f224ddd4.0", + "@material/linear-progress": "15.0.0-canary.7f224ddd4.0", + "@material/list": "15.0.0-canary.7f224ddd4.0", + "@material/menu": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/select": "15.0.0-canary.7f224ddd4.0", + "@material/shape": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/tokens": "15.0.0-canary.7f224ddd4.0", + "@material/touch-target": "15.0.0-canary.7f224ddd4.0", + "@material/typography": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" + } }, - "node_modules/@jest/reporters/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, + "node_modules/@material/density": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/density/-/density-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-o9EXmGKVpiQ6mHhyV3oDDzc78Ow3E7v8dlaOhgaDSXgmqaE8v5sIlLNa/LKSyUga83/fpGk3QViSGXotpQx0jA==", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "tslib": "^2.1.0" } }, - "node_modules/@jest/reporters/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" + "node_modules/@material/dialog": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/dialog/-/dialog-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-u0XpTlv1JqWC/bQ3DavJ1JguofTelLT2wloj59l3/1b60jv42JQ6Am7jU3I8/SIUB1MKaW7dYocXjDWtWJakLA==", + "dependencies": { + "@material/animation": "15.0.0-canary.7f224ddd4.0", + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/button": "15.0.0-canary.7f224ddd4.0", + "@material/dom": "15.0.0-canary.7f224ddd4.0", + "@material/elevation": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/icon-button": "15.0.0-canary.7f224ddd4.0", + "@material/ripple": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/shape": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/tokens": "15.0.0-canary.7f224ddd4.0", + "@material/touch-target": "15.0.0-canary.7f224ddd4.0", + "@material/typography": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@jest/reporters/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, + "node_modules/@material/dom": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/dom/-/dom-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-mQ1HT186GPQSkRg5S18i70typ5ZytfjL09R0gJ2Qg5/G+MLCGi7TAjZZSH65tuD/QGOjel4rDdWOTmYbPYV6HA==", "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@jest/reporters/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, + "node_modules/@material/drawer": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/drawer/-/drawer-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-qyO0W0KBftfH8dlLR0gVAgv7ZHNvU8ae11Ao6zJif/YxcvK4+gph1z8AO4H410YmC2kZiwpSKyxM1iQCCzbb4g==", + "dependencies": { + "@material/animation": "15.0.0-canary.7f224ddd4.0", + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/dom": "15.0.0-canary.7f224ddd4.0", + "@material/elevation": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/list": "15.0.0-canary.7f224ddd4.0", + "@material/ripple": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/shape": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/typography": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/elevation": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-tV6s4/pUBECedaI36Yj18KmRCk1vfue/JP/5yYRlFNnLMRVISePbZaKkn/BHXVf+26I3W879+XqIGlDVdmOoMA==", "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "@material/animation": "15.0.0-canary.7f224ddd4.0", + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@jest/schemas": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", - "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", - "dev": true, + "node_modules/@material/fab": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/fab/-/fab-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-4h76QrzfZTcPdd+awDPZ4Q0YdSqsXQnS540TPtyXUJ/5G99V6VwGpjMPIxAsW0y+pmI9UkLL/srrMaJec+7r4Q==", + "dependencies": { + "@material/animation": "15.0.0-canary.7f224ddd4.0", + "@material/dom": "15.0.0-canary.7f224ddd4.0", + "@material/elevation": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/focus-ring": "15.0.0-canary.7f224ddd4.0", + "@material/ripple": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/shape": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/tokens": "15.0.0-canary.7f224ddd4.0", + "@material/touch-target": "15.0.0-canary.7f224ddd4.0", + "@material/typography": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/feature-targeting": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/feature-targeting/-/feature-targeting-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-SAjtxYh6YlKZriU83diDEQ7jNSP2MnxKsER0TvFeyG1vX/DWsUyYDOIJTOEa9K1N+fgJEBkNK8hY55QhQaspew==", "dependencies": { - "@sinclair/typebox": "^0.24.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "tslib": "^2.1.0" } }, - "node_modules/@jest/source-map": { - "version": "28.1.2", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.1.2.tgz", - "integrity": "sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww==", - "dev": true, + "node_modules/@material/floating-label": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/floating-label/-/floating-label-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-0KMo5ijjYaEHPiZ2pCVIcbaTS2LycvH9zEhEMKwPPGssBCX7iz5ffYQFk7e5yrQand1r3jnQQgYfHAwtykArnQ==", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.13", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "@material/animation": "15.0.0-canary.7f224ddd4.0", + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/dom": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/typography": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@jest/test-result": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.3.tgz", - "integrity": "sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==", - "dev": true, + "node_modules/@material/focus-ring": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/focus-ring/-/focus-ring-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-Jmg1nltq4J6S6A10EGMZnvufrvU3YTi+8R8ZD9lkSbun0Fm2TVdICQt/Auyi6An9zP66oQN6c31eqO6KfIPsDg==", "dependencies": { - "@jest/console": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "@material/dom": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0" } }, - "node_modules/@jest/test-sequencer": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.1.3.tgz", - "integrity": "sha512-NIMPEqqa59MWnDi1kvXXpYbqsfQmSJsIbnd85mdVGkiDfQ9WQQTXOLsvISUfonmnBT+w85WEgneCigEEdHDFxw==", - "dev": true, + "node_modules/@material/form-field": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/form-field/-/form-field-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-fEPWgDQEPJ6WF7hNnIStxucHR9LE4DoDSMqCsGWS2Yu+NLZYLuCEecgR0UqQsl1EQdNRaFh8VH93KuxGd2hiPg==", "dependencies": { - "@jest/test-result": "^28.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.3", - "slash": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/ripple": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/typography": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@jest/transform": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", - "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", - "dev": true, + "node_modules/@material/icon-button": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/icon-button/-/icon-button-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-DcK7IL4ICY/DW+48YQZZs9g0U1kRaW0Wb0BxhvppDMYziHo/CTpFdle4gjyuTyRxPOdHQz5a97ru48Z9O4muTw==", + "dependencies": { + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/density": "15.0.0-canary.7f224ddd4.0", + "@material/dom": "15.0.0-canary.7f224ddd4.0", + "@material/elevation": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/focus-ring": "15.0.0-canary.7f224ddd4.0", + "@material/ripple": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/touch-target": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/image-list": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/image-list/-/image-list-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-voMjG2p80XbjL1B2lmF65zO5gEgJOVKClLdqh4wbYzYfwY/SR9c8eLvlYG7DLdFaFBl/7gGxD8TvvZ329HUFPw==", "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^28.1.3", - "@jridgewell/trace-mapping": "^0.3.13", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.3", - "jest-regex-util": "^28.0.2", - "jest-util": "^28.1.3", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/shape": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/typography": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@jest/transform/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "node_modules/@material/layout-grid": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/layout-grid/-/layout-grid-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-veDABLxMn2RmvfnUO2RUmC1OFfWr4cU+MrxKPoDD2hl3l3eDYv5fxws6r5T1JoSyXoaN+oEZpheS0+M9Ure8Pg==", "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "tslib": "^2.1.0" } }, - "node_modules/@jest/transform/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "node_modules/@material/line-ripple": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/line-ripple/-/line-ripple-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-f60hVJhIU6I3/17Tqqzch1emUKEcfVVgHVqADbU14JD+oEIz429ZX9ksZ3VChoU3+eejFl+jVdZMLE/LrAuwpg==", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "@material/animation": "15.0.0-canary.7f224ddd4.0", + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@jest/transform/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "node_modules/@material/linear-progress": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/linear-progress/-/linear-progress-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-pRDEwPQielDiC9Sc5XhCXrGxP8wWOnAO8sQlMebfBYHYqy5hhiIzibezS8CSaW4MFQFyXmCmpmqWlbqGYRmiyg==", "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "@material/animation": "15.0.0-canary.7f224ddd4.0", + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/dom": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/progress-indicator": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@jest/transform/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "node_modules/@material/list": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/list/-/list-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-Is0NV91sJlXF5pOebYAtWLF4wU2MJDbYqztML/zQNENkQxDOvEXu3nWNb3YScMIYJJXvARO0Liur5K4yPagS1Q==", + "dependencies": { + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/density": "15.0.0-canary.7f224ddd4.0", + "@material/dom": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/ripple": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/shape": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/tokens": "15.0.0-canary.7f224ddd4.0", + "@material/typography": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" + } }, - "node_modules/@jest/transform/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" + "node_modules/@material/menu": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/menu/-/menu-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-D11QU1dXqLbh5X1zKlEhS3QWh0b5BPNXlafc5MXfkdJHhOiieb7LC9hMJhbrHtj24FadJ7evaFW/T2ugJbJNnQ==", + "dependencies": { + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/dom": "15.0.0-canary.7f224ddd4.0", + "@material/elevation": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/list": "15.0.0-canary.7f224ddd4.0", + "@material/menu-surface": "15.0.0-canary.7f224ddd4.0", + "@material/ripple": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/shape": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/tokens": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@jest/transform/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, + "node_modules/@material/menu-surface": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/menu-surface/-/menu-surface-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-7RZHvw0gbwppaAJ/Oh5SWmfAKJ62aw1IMB3+3MRwsb5PLoV666wInYa+zJfE4i7qBeOn904xqT2Nko5hY0ssrg==", "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "@material/animation": "15.0.0-canary.7f224ddd4.0", + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/elevation": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/shape": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@jest/types": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", - "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", - "dev": true, + "node_modules/@material/notched-outline": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/notched-outline/-/notched-outline-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-Yg2usuKB2DKlKIBISbie9BFsOVuffF71xjbxPbybvqemxqUBd+bD5/t6H1fLE+F8/NCu5JMigho4ewUU+0RCiw==", "dependencies": { - "@jest/schemas": "^28.1.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/floating-label": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/shape": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@jest/types/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "node_modules/@material/progress-indicator": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/progress-indicator/-/progress-indicator-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-UPbDjE5CqT+SqTs0mNFG6uFEw7wBlgYmh+noSkQ6ty/EURm8lF125dmi4dv4kW0+octonMXqkGtAoZwLIHKf/w==", "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "tslib": "^2.1.0" } }, - "node_modules/@jest/types/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "node_modules/@material/radio": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/radio/-/radio-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-wR1X0Sr0KmQLu6+YOFKAI84G3L6psqd7Kys5kfb8WKBM36zxO5HQXC5nJm/Y0rdn22ixzsIz2GBo0MNU4V4k1A==", + "dependencies": { + "@material/animation": "15.0.0-canary.7f224ddd4.0", + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/density": "15.0.0-canary.7f224ddd4.0", + "@material/dom": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/focus-ring": "15.0.0-canary.7f224ddd4.0", + "@material/ripple": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/touch-target": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/ripple": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-JqOsWM1f4aGdotP0rh1vZlPZTg6lZgh39FIYHFMfOwfhR+LAikUJ+37ciqZuewgzXB6iiRO6a8aUH6HR5SJYPg==", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "@material/animation": "15.0.0-canary.7f224ddd4.0", + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/dom": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@jest/types/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "node_modules/@material/rtl": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-UVf14qAtmPiaaZjuJtmN36HETyoKWmsZM/qn1L5ciR2URb8O035dFWnz4ZWFMmAYBno/L7JiZaCkPurv2ZNrGA==", "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@jest/types/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "node_modules/@material/segmented-button": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/segmented-button/-/segmented-button-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-LCnVRUSAhELTKI/9hSvyvIvQIpPpqF29BV+O9yM4WoNNmNWqTulvuiv7grHZl6Z+kJuxSg4BGbsPxxb9dXozPg==", + "dependencies": { + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/elevation": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/ripple": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/touch-target": "15.0.0-canary.7f224ddd4.0", + "@material/typography": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" + } }, - "node_modules/@jest/types/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" + "node_modules/@material/select": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/select/-/select-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-WioZtQEXRpglum0cMSzSqocnhsGRr+ZIhvKb3FlaNrTaK8H3Y4QA7rVjv3emRtrLOOjaT6/RiIaUMTo9AGzWQQ==", + "dependencies": { + "@material/animation": "15.0.0-canary.7f224ddd4.0", + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/density": "15.0.0-canary.7f224ddd4.0", + "@material/dom": "15.0.0-canary.7f224ddd4.0", + "@material/elevation": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/floating-label": "15.0.0-canary.7f224ddd4.0", + "@material/line-ripple": "15.0.0-canary.7f224ddd4.0", + "@material/list": "15.0.0-canary.7f224ddd4.0", + "@material/menu": "15.0.0-canary.7f224ddd4.0", + "@material/menu-surface": "15.0.0-canary.7f224ddd4.0", + "@material/notched-outline": "15.0.0-canary.7f224ddd4.0", + "@material/ripple": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/shape": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/tokens": "15.0.0-canary.7f224ddd4.0", + "@material/typography": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@jest/types/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, + "node_modules/@material/shape": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/shape/-/shape-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-8z8l1W3+cymObunJoRhwFPKZ+FyECfJ4MJykNiaZq7XJFZkV6xNmqAVrrbQj93FtLsECn9g4PjjIomguVn/OEw==", "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - }, - "engines": { - "node": ">=6.0.0" + "node_modules/@material/slider": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/slider/-/slider-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-QU/WSaSWlLKQRqOhJrPgm29wqvvzRusMqwAcrCh1JTrCl+xwJ43q5WLDfjYhubeKtrEEgGu9tekkAiYfMG7EBw==", + "dependencies": { + "@material/animation": "15.0.0-canary.7f224ddd4.0", + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/dom": "15.0.0-canary.7f224ddd4.0", + "@material/elevation": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/ripple": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/tokens": "15.0.0-canary.7f224ddd4.0", + "@material/typography": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "engines": { - "node": ">=6.0.0" + "node_modules/@material/snackbar": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/snackbar/-/snackbar-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-sm7EbVKddaXpT/aXAYBdPoN0k8yeg9+dprgBUkrdqGzWJAeCkxb4fv2B3He88YiCtvkTz2KLY4CThPQBSEsMFQ==", + "dependencies": { + "@material/animation": "15.0.0-canary.7f224ddd4.0", + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/button": "15.0.0-canary.7f224ddd4.0", + "@material/dom": "15.0.0-canary.7f224ddd4.0", + "@material/elevation": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/icon-button": "15.0.0-canary.7f224ddd4.0", + "@material/ripple": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/shape": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/tokens": "15.0.0-canary.7f224ddd4.0", + "@material/typography": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "engines": { - "node": ">=6.0.0" + "node_modules/@material/switch": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/switch/-/switch-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-lEDJfRvkVyyeHWIBfoxYjJVl+WlEAE2kZ/+6OqB1FW0OV8ftTODZGhHRSzjVBA1/p4FPuhAtKtoK9jTpa4AZjA==", + "dependencies": { + "@material/animation": "15.0.0-canary.7f224ddd4.0", + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/density": "15.0.0-canary.7f224ddd4.0", + "@material/dom": "15.0.0-canary.7f224ddd4.0", + "@material/elevation": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/focus-ring": "15.0.0-canary.7f224ddd4.0", + "@material/ripple": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/shape": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/tokens": "15.0.0-canary.7f224ddd4.0", + "safevalues": "^0.3.4", + "tslib": "^2.1.0" } }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", - "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", - "dev": true, + "node_modules/@material/tab": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/tab/-/tab-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-E1xGACImyCLurhnizyOTCgOiVezce4HlBFAI6YhJo/AyVwjN2Dtas4ZLQMvvWWqpyhITNkeYdOchwCC1mrz3AQ==", + "dependencies": { + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/elevation": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/focus-ring": "15.0.0-canary.7f224ddd4.0", + "@material/ripple": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/tab-indicator": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/tokens": "15.0.0-canary.7f224ddd4.0", + "@material/typography": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/tab-bar": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/tab-bar/-/tab-bar-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-p1Asb2NzrcECvAQU3b2SYrpyJGyJLQWR+nXTYzDKE8WOpLIRCXap2audNqD7fvN/A20UJ1J8U01ptrvCkwJ4eA==", + "dependencies": { + "@material/animation": "15.0.0-canary.7f224ddd4.0", + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/density": "15.0.0-canary.7f224ddd4.0", + "@material/elevation": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/tab": "15.0.0-canary.7f224ddd4.0", + "@material/tab-indicator": "15.0.0-canary.7f224ddd4.0", + "@material/tab-scroller": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/tokens": "15.0.0-canary.7f224ddd4.0", + "@material/typography": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@material/tab-indicator": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/tab-indicator/-/tab-indicator-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-h9Td3MPqbs33spcPS7ecByRHraYgU4tNCZpZzZXw31RypjKvISDv/PS5wcA4RmWqNGih78T7xg4QIGsZg4Pk4w==", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" + "@material/animation": "15.0.0-canary.7f224ddd4.0", + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, + "node_modules/@material/tab-scroller": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/tab-scroller/-/tab-scroller-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-LFeYNjQpdXecwECd8UaqHYbhscDCwhGln5Yh+3ctvcEgvmDPNjhKn/DL3sWprWvG8NAhP6sHMrsGhQFVdCWtTg==", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" + "@material/animation": "15.0.0-canary.7f224ddd4.0", + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/dom": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/tab": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + "node_modules/@material/textfield": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/textfield/-/textfield-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-AExmFvgE5nNF0UA4l2cSzPghtxSUQeeoyRjFLHLy+oAaE4eKZFrSy0zEpqPeWPQpEMDZk+6Y+6T3cOFYBeSvsw==", + "dependencies": { + "@material/animation": "15.0.0-canary.7f224ddd4.0", + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/density": "15.0.0-canary.7f224ddd4.0", + "@material/dom": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/floating-label": "15.0.0-canary.7f224ddd4.0", + "@material/line-ripple": "15.0.0-canary.7f224ddd4.0", + "@material/notched-outline": "15.0.0-canary.7f224ddd4.0", + "@material/ripple": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/shape": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/tokens": "15.0.0-canary.7f224ddd4.0", + "@material/typography": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" + } }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "node_modules/@material/theme": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-hs45hJoE9yVnoVOcsN1jklyOa51U4lzWsEnQEuJTPOk2+0HqCQ0yv/q0InpSnm2i69fNSyZC60+8HADZGF8ugQ==", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", - "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", - "dev": true + "node_modules/@material/tokens": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/tokens/-/tokens-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-r9TDoicmcT7FhUXC4eYMFnt9TZsz0G8T3wXvkKncLppYvZ517gPyD/1+yhuGfGOxAzxTrM66S/oEc1fFE2q4hw==", + "dependencies": { + "@material/elevation": "15.0.0-canary.7f224ddd4.0" + } }, - "node_modules/@lukeed/ms": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@lukeed/ms/-/ms-2.0.2.tgz", - "integrity": "sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA==", - "engines": { - "node": ">=8" + "node_modules/@material/tooltip": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/tooltip/-/tooltip-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-8qNk3pmPLTnam3XYC1sZuplQXW9xLn4Z4MI3D+U17Q7pfNZfoOugGr+d2cLA9yWAEjVJYB0mj8Yu86+udo4N9w==", + "dependencies": { + "@material/animation": "15.0.0-canary.7f224ddd4.0", + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/button": "15.0.0-canary.7f224ddd4.0", + "@material/dom": "15.0.0-canary.7f224ddd4.0", + "@material/elevation": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/shape": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/tokens": "15.0.0-canary.7f224ddd4.0", + "@material/typography": "15.0.0-canary.7f224ddd4.0", + "safevalues": "^0.3.4", + "tslib": "^2.1.0" } }, - "node_modules/@ngneat/until-destroy": { - "version": "9.2.3", - "resolved": "https://registry.npmjs.org/@ngneat/until-destroy/-/until-destroy-9.2.3.tgz", - "integrity": "sha512-ryX0vqDOdmYo53f7v5Ivbj1jcqOEX+vM1iiV9NYepWDha4VJp9lWrDFK9tRt2evAMzF/9u67JLzs4Xjcoh+Taw==", - "dev": true, + "node_modules/@material/top-app-bar": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/top-app-bar/-/top-app-bar-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-SARR5/ClYT4CLe9qAXakbr0i0cMY0V3V4pe3ElIJPfL2Z2c4wGR1mTR8m2LxU1MfGKK8aRoUdtfKaxWejp+eNA==", "dependencies": { - "tslib": "^2.3.0" - }, - "peerDependencies": { - "@angular/core": ">=13", - "rxjs": "^6.4.0 || ^7.0.0" + "@material/animation": "15.0.0-canary.7f224ddd4.0", + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/elevation": "15.0.0-canary.7f224ddd4.0", + "@material/ripple": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/shape": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "@material/typography": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@ngtools/webpack": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-14.1.3.tgz", - "integrity": "sha512-tP2aiWKezhOVcR/PhVHcxKohO4ShKrhD42wgbJPbcqHeenOv1Hf5nW1nyUviqeF8QbVmPdBPF/ZOB8hIq5o6sw==", - "dev": true, - "engines": { - "node": "^14.15.0 || >=16.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "@angular/compiler-cli": "^14.0.0", - "typescript": ">=4.6.2 <4.8", - "webpack": "^5.54.0" + "node_modules/@material/touch-target": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/touch-target/-/touch-target-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-BJo/wFKHPYLGsRaIpd7vsQwKr02LtO2e89Psv0on/p0OephlNIgeB9dD9W+bQmaeZsZ6liKSKRl6wJWDiK71PA==", + "dependencies": { + "@material/base": "15.0.0-canary.7f224ddd4.0", + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/rtl": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@ngx-rocket/ascii-logo": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@ngx-rocket/ascii-logo/-/ascii-logo-1.1.0.tgz", - "integrity": "sha512-iGTX2tIAQmo/z2xiOsTAMxvO4wwHJkmutTzfJ+T/0Ebig54e1L2kgvctFRVHSj86UQUn8duzpuzcJJ4K4NK4jg==", - "dev": true, + "node_modules/@material/typography": { + "version": "15.0.0-canary.7f224ddd4.0", + "resolved": "https://registry.npmjs.org/@material/typography/-/typography-15.0.0-canary.7f224ddd4.0.tgz", + "integrity": "sha512-kBaZeCGD50iq1DeRRH5OM5Jl7Gdk+/NOfKArkY4ksBZvJiStJ7ACAhpvb8MEGm4s3jvDInQFLsDq3hL+SA79sQ==", "dependencies": { - "chalk": "^2.0.1" - }, - "engines": { - "node": ">=6.0.0" + "@material/feature-targeting": "15.0.0-canary.7f224ddd4.0", + "@material/theme": "15.0.0-canary.7f224ddd4.0", + "tslib": "^2.1.0" } }, - "node_modules/@ngx-rocket/scripts": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@ngx-rocket/scripts/-/scripts-5.2.3.tgz", - "integrity": "sha512-024H2U1H/07ISfkt/PMXOp3sl3+bWbncsjPVgxzU9eAAkNxkt56Z/Llzy46l6h2fsrGkjiGvUMFKGHWQawCgJg==", - "dev": true, + "node_modules/@mermaid-js/parser": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-0.3.0.tgz", + "integrity": "sha512-HsvL6zgE5sUPGgkIDlmAWR1HTNHz2Iy11BAWPTa4Jjabkpguy4Ze2gzfLrg6pdRuBvFwgUYyxiaNqZwrEEXepA==", + "optional": true, "dependencies": { - "@ngx-rocket/ascii-logo": "^1.1.0", - "chalk": "^4.1.0", - "fs-extra": "^10.0.0", - "lodash.get": "^4.4.2", - "minimist": "^1.2.5" - }, - "bin": { - "ngx-scripts": "bin/ngx-scripts" - }, - "engines": { - "node": ">=14.0.0" + "langium": "3.0.0" } }, - "node_modules/@ngx-rocket/scripts/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz", + "integrity": "sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@ngx-rocket/scripts/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.2.tgz", + "integrity": "sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@ngx-rocket/scripts/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.2.tgz", + "integrity": "sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA==", + "cpu": [ + "arm" + ], "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@ngx-rocket/scripts/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.2.tgz", + "integrity": "sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@ngx-rocket/scripts/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.2.tgz", + "integrity": "sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA==", + "cpu": [ + "x64" + ], "dev": true, - "engines": { - "node": ">=8" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@ngx-rocket/scripts/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz", + "integrity": "sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "has-flag": "^4.0.0" + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@ngneat/transloco": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@ngneat/transloco/-/transloco-6.0.4.tgz", + "integrity": "sha512-hQSPdmzuxJIu2SBwvoiwjoUjxSnUGFyCOkJnV8IwzzmBSdgQxqMMci5WXg/bQeCYggA+RyXpUjjTudEvkWy5Rw==", + "dependencies": { + "@ngneat/transloco-utils": "^5.0.0", + "flat": "6.0.1", + "fs-extra": "^11.0.0", + "glob": "^10.0.0", + "lodash.kebabcase": "^4.1.1", + "ora": "^5.4.1", + "replace-in-file": "^7.0.1", + "tslib": "^2.2.0" }, - "engines": { - "node": ">=8" + "peerDependencies": { + "@angular/core": ">=16.0.0" } }, - "node_modules/@ngx-translate/core": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-14.0.0.tgz", - "integrity": "sha512-UevdwNCXMRCdJv//0kC8h2eSfmi02r29xeE8E9gJ1Al4D4jEJ7eiLPdjslTMc21oJNGguqqWeEVjf64SFtvw2w==", + "node_modules/@ngneat/transloco-utils": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@ngneat/transloco-utils/-/transloco-utils-5.0.0.tgz", + "integrity": "sha512-e0S+GWyBTmLix9KfYWW/rScYdqQz3z3znNSb+foaA5T3jWs4CPLVo+PV0No7kGjqom8Wy8H3lLvztfhHxYSLyA==", "dependencies": { + "cosmiconfig": "^8.1.3", "tslib": "^2.3.0" }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@ngtools/webpack": { + "version": "18.0.2", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.0.2.tgz", + "integrity": "sha512-I+ZNFGBnykUWBwGPCXy6m9R2fIX/ovnAUHylvThYd/M+FUfc+Z/3DpKEUBYIOLVCLNZR5nuK0t9QLlazYhWFgg==", + "dev": true, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, "peerDependencies": { - "@angular/core": ">=13.0.0", - "rxjs": "^6.5.3 || ^7.4.0" + "@angular/compiler-cli": "^18.0.0", + "typescript": ">=5.4 <5.5", + "webpack": "^5.54.0" } }, "node_modules/@nodelib/fs.scandir": { @@ -4688,191 +4637,222 @@ "node": ">= 8" } }, + "node_modules/@npmcli/agent": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz", + "integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, "node_modules/@npmcli/fs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", - "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", + "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==", "dev": true, "dependencies": { - "@gar/promisify": "^1.1.3", "semver": "^7.3.5" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/@npmcli/git": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-3.0.2.tgz", - "integrity": "sha512-CAcd08y3DWBJqJDpfuVL0uijlq5oaXaOJEKHKc4wqrjd00gkvTZB+nFuLn+doOOKddaQS9JfqtNoFCO2LCvA3w==", + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.7.tgz", + "integrity": "sha512-WaOVvto604d5IpdCRV2KjQu8PzkfE96d50CQGKgywXh2GxXmDeUO5EWcBC4V57uFyrNqx83+MewuJh3WTR3xPA==", "dev": true, "dependencies": { - "@npmcli/promise-spawn": "^3.0.0", - "lru-cache": "^7.4.4", - "mkdirp": "^1.0.4", - "npm-pick-manifest": "^7.0.0", - "proc-log": "^2.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^9.0.0", + "proc-log": "^4.0.0", "promise-inflight": "^1.0.1", "promise-retry": "^2.0.1", "semver": "^7.3.5", - "which": "^2.0.2" + "which": "^4.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" } }, "node_modules/@npmcli/git/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", "dev": true, "engines": { - "node": ">=12" + "node": "14 || >=16.14" } }, - "node_modules/@npmcli/installed-package-contents": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz", - "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", + "node_modules/@npmcli/git/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", "dev": true, "dependencies": { - "npm-bundled": "^1.1.1", - "npm-normalize-package-bin": "^1.0.1" + "isexe": "^3.1.1" }, "bin": { - "installed-package-contents": "index.js" + "node-which": "bin/which.js" }, "engines": { - "node": ">= 10" + "node": "^16.13.0 || >=18.0.0" } }, - "node_modules/@npmcli/move-file": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", - "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", - "deprecated": "This functionality has been moved to @npmcli/fs", + "node_modules/@npmcli/installed-package-contents": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.1.0.tgz", + "integrity": "sha512-c8UuGLeZpm69BryRykLuKRyKFZYJsZSCT4aVY5ds4omyZqJ172ApzgfKJ5eV/r3HgLdUYgFVe54KSFVjKoe27w==", "dev": true, "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "bin": { + "installed-package-contents": "bin/index.js" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/@npmcli/node-gyp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-2.0.0.tgz", - "integrity": "sha512-doNI35wIe3bBaEgrlPfdJPaCpUR89pJWep4Hq3aRdh6gKazIVWfs0jHttvSSoq47ZXgC7h73kDsUl8AoIQUB+A==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", + "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", "dev": true, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/@npmcli/promise-spawn": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-3.0.0.tgz", - "integrity": "sha512-s9SgS+p3a9Eohe68cSI3fi+hpcZUmXq5P7w0kMlAsWVtR7XbK3ptkZqKT2cK1zLDObJ3sR+8P59sJE0w/KTL1g==", + "node_modules/@npmcli/package-json": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-5.1.0.tgz", + "integrity": "sha512-1aL4TuVrLS9sf8quCLerU3H9J4vtCtgu8VauYozrmEyU57i/EdKleCnsQ7vpnABIH6c9mnTxcH5sFkO3BlV8wQ==", "dev": true, "dependencies": { - "infer-owner": "^1.0.4" + "@npmcli/git": "^5.0.0", + "glob": "^10.2.2", + "hosted-git-info": "^7.0.0", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "proc-log": "^4.0.0", + "semver": "^7.5.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@npmcli/run-script": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-4.2.1.tgz", - "integrity": "sha512-7dqywvVudPSrRCW5nTHpHgeWnbBtz8cFkOuKrecm6ih+oO9ciydhWt6OF7HlqupRRmB8Q/gECVdB9LMfToJbRg==", + "node_modules/@npmcli/promise-spawn": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.2.tgz", + "integrity": "sha512-xhfYPXoV5Dy4UkY0D+v2KkwvnDfiA/8Mt3sWCGI/hM03NsYIH8ZaG6QzS9x7pje5vHZBZJ2v6VRFVTWACnqcmQ==", "dev": true, "dependencies": { - "@npmcli/node-gyp": "^2.0.0", - "@npmcli/promise-spawn": "^3.0.0", - "node-gyp": "^9.0.0", - "read-package-json-fast": "^2.0.3", - "which": "^2.0.2" + "which": "^4.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@nrwl/cli": { - "version": "14.8.9", - "resolved": "https://registry.npmjs.org/@nrwl/cli/-/cli-14.8.9.tgz", - "integrity": "sha512-NsnVfM4B4Fqjvu9a9ZeJAzDKQclKeyWvSMXLGCebzsKcIBwbeh6G30nmVV8Z8VkdaJDOvle6QsYSVVNrl416fw==", + "node_modules/@npmcli/promise-spawn/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "dev": true, - "dependencies": { - "nx": "14.8.9" + "engines": { + "node": ">=16" } }, - "node_modules/@nrwl/devkit": { - "version": "14.8.9", - "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-14.8.9.tgz", - "integrity": "sha512-C9PxTxTrVundP9xDbub7apkMPP1v1PSIu/d82VdOVnnU3Kvc2fRX2gafSdH+BMBP3SE4bIBblQI6gUuDXbYubw==", + "node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", "dev": true, "dependencies": { - "@phenomnomnominal/tsquery": "4.1.1", - "ejs": "^3.1.7", - "ignore": "^5.0.4", - "tslib": "^2.3.0" + "isexe": "^3.1.1" }, - "peerDependencies": { - "nx": ">= 13.10 <= 15" + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" } }, - "node_modules/@nrwl/devkit/node_modules/@phenomnomnominal/tsquery": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@phenomnomnominal/tsquery/-/tsquery-4.1.1.tgz", - "integrity": "sha512-jjMmK1tnZbm1Jq5a7fBliM4gQwjxMU7TFoRNwIyzwlO+eHPRCFv/Nv+H/Gi1jc3WR7QURG8D5d0Tn12YGrUqBQ==", + "node_modules/@npmcli/redact": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-2.0.0.tgz", + "integrity": "sha512-SEjCPAVHWYUIQR+Yn03kJmrJjZDtJLYpj300m3HV9OTRZNpC5YpbMsM3eTkECyT4aWj8lDr9WeY6TWefpubtYQ==", "dev": true, - "dependencies": { - "esquery": "^1.0.1" - }, - "peerDependencies": { - "typescript": "^3 || ^4" + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@nrwl/tao": { - "version": "14.8.9", - "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-14.8.9.tgz", - "integrity": "sha512-llaZvTCXUmj4WtpbnjZOOzyTWcZIkj7gmtY5sa1nrTvbls9BaFRabOvfW4/z3s3E3iavni9ENMuuaHOfHyiRkg==", + "node_modules/@npmcli/run-script": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-8.1.0.tgz", + "integrity": "sha512-y7efHHwghQfk28G2z3tlZ67pLG0XdfYbcVG26r7YIXALRsrVQcTq4/tdenSmdOrEsNahIYA/eh8aEVROWGFUDg==", "dev": true, "dependencies": { - "nx": "14.8.9" + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "node-gyp": "^10.0.0", + "proc-log": "^4.0.0", + "which": "^4.0.0" }, - "bin": { - "tao": "index.js" + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@parcel/watcher": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.0.4.tgz", - "integrity": "sha512-cTDi+FUDBIUOBKEtj+nhiJ71AZVlkAsQFuGQTun5tV9mwQBQgZvhCzG+URPQc8myeN32yRVZEfVAPCs1RW+Jvg==", + "node_modules/@npmcli/run-script/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "dev": true, - "hasInstallScript": true, - "dependencies": { - "node-addon-api": "^3.2.1", - "node-gyp-build": "^4.3.0" - }, "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">=16" } }, - "node_modules/@phenomnomnominal/tsquery": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@phenomnomnominal/tsquery/-/tsquery-4.2.0.tgz", - "integrity": "sha512-hR2U3uVcrrdkuG30ItQ+uFDs4ncZAybxWG0OjTE8ptPzVoU7GVeXpy+vMU8zX9EbmjGeITPw/su5HjYQyAH8bA==", + "node_modules/@npmcli/run-script/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", "dev": true, "dependencies": { - "esquery": "^1.0.1" + "isexe": "^3.1.1" }, - "peerDependencies": { - "typescript": "^3 || ^4" + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" } }, "node_modules/@pkgjs/parseargs": { @@ -4884,174 +4864,345 @@ "node": ">=14" } }, - "node_modules/@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz", + "integrity": "sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==", + "cpu": [ + "arm" + ], "dev": true, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } + "optional": true, + "os": [ + "android" + ] }, - "node_modules/@schematics/angular": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-14.1.3.tgz", - "integrity": "sha512-hhH4MGfBD1oxrd9PFZwgaqXAT9dYTK/6AtoIcr40OwEbnS5ZoZwzrgb0OOT2NW3bmL0dg3YeJei3Sf89hlI5eg==", + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz", + "integrity": "sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "@angular-devkit/core": "14.1.3", - "@angular-devkit/schematics": "14.1.3", - "jsonc-parser": "3.1.0" - }, - "engines": { - "node": "^14.15.0 || >=16.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } + "optional": true, + "os": [ + "android" + ] }, - "node_modules/@schematics/angular/node_modules/@angular-devkit/core": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.1.3.tgz", - "integrity": "sha512-YBxhRl7hKgirjcKeurfejVrIgmw31GcfKKCyQiIudoLCYjonnSMdDEx2y8BNMANvxe5YmuZsIYJtgVlqp3mMDg==", + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz", + "integrity": "sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "ajv": "8.11.0", - "ajv-formats": "2.1.1", - "jsonc-parser": "3.1.0", - "rxjs": "6.6.7", - "source-map": "0.7.4" - }, - "engines": { - "node": "^14.15.0 || >=16.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^3.5.2" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@schematics/angular/node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz", + "integrity": "sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@schematics/angular/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz", + "integrity": "sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@sinclair/typebox": { - "version": "0.24.51", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", - "dev": true + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz", + "integrity": "sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz", + "integrity": "sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz", + "integrity": "sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz", + "integrity": "sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz", + "integrity": "sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz", + "integrity": "sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz", + "integrity": "sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz", + "integrity": "sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz", + "integrity": "sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz", + "integrity": "sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz", + "integrity": "sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@sinonjs/commons": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", - "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "node_modules/@schematics/angular": { + "version": "18.0.2", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-18.0.2.tgz", + "integrity": "sha512-qkJs1oxHtneJ6QxDKpxNyneXGDM9SKVj+Bgi8xUAU3FEzpsYmE/aW3MfwYHOZl0pDBO8c2raqLvlyl3dGP6/Gg==", "dev": true, "dependencies": { - "type-detect": "4.0.8" + "@angular-devkit/core": "18.0.2", + "@angular-devkit/schematics": "18.0.2", + "jsonc-parser": "3.2.1" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" } }, - "node_modules/@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "node_modules/@sigstore/bundle": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.3.2.tgz", + "integrity": "sha512-wueKWDk70QixNLB363yHc2D2ItTgYiMTdPwK8D9dKQMR3ZQ0c35IxP5xnwQ8cNLoCgCRcHf14kE+CLIvNX1zmA==", "dev": true, "dependencies": { - "@sinonjs/commons": "^1.7.0" + "@sigstore/protobuf-specs": "^0.3.2" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "node_modules/@sigstore/core": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-1.1.0.tgz", + "integrity": "sha512-JzBqdVIyqm2FRQCulY6nbQzMpJJpSiJ8XXWMhtOX9eKgaXXpfNOF53lzQEjIydlStnd/eFtuC1dW4VYdD93oRg==", "dev": true, "engines": { - "node": ">= 10" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@tsconfig/node10": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true + "node_modules/@sigstore/protobuf-specs": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.3.2.tgz", + "integrity": "sha512-c6B0ehIWxMI8wiS/bj6rHMPqeFvngFV7cDU/MY+B16P9Z3Mp9k8L93eYZ7BYzSickzuqAQqAq0V956b3Ju6mLw==", + "dev": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true + "node_modules/@sigstore/sign": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.3.2.tgz", + "integrity": "sha512-5Vz5dPVuunIIvC5vBb0APwo7qKA4G9yM48kPWJT+OEERs40md5GoUR1yedwpekWZ4m0Hhw44m6zU+ObsON+iDA==", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^2.3.2", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.2", + "make-fetch-happen": "^13.0.1", + "proc-log": "^4.2.0", + "promise-retry": "^2.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "node_modules/@sigstore/tuf": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.4.tgz", + "integrity": "sha512-44vtsveTPUpqhm9NCrbU8CWLe3Vck2HO1PNLw7RIajbB7xhtn5RBPm1VNSCMwqGYHhDsBJG8gDF0q4lgydsJvw==", "dev": true, "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" + "@sigstore/protobuf-specs": "^0.3.2", + "tuf-js": "^2.2.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@types/babel__generator": { - "version": "7.6.8", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", - "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "node_modules/@sigstore/verify": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-1.2.1.tgz", + "integrity": "sha512-8iKx79/F73DKbGfRf7+t4dqrc0bRr0thdPrxAtCKWRm/F0tG71i6O1rvlnScncJLLBZHn3h8M3c1BSUAb9yu8g==", "dev": true, "dependencies": { - "@babel/types": "^7.0.0" + "@sigstore/bundle": "^2.3.2", + "@sigstore/core": "^1.1.0", + "@sigstore/protobuf-specs": "^0.3.2" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", + "dev": true + }, + "node_modules/@tailwindcss/typography": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.13.tgz", + "integrity": "sha512-ADGcJ8dX21dVVHIwTRgzrcunY6YY9uSlAHHGVKvkA+vLc5qLwEszvKts40lx7z0qc4clpjclwLeK5rVCV2P/uw==", "dev": true, "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" + "lodash.castarray": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "postcss-selector-parser": "6.0.10" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders" + } + }, + "node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", + "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", + "dev": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@types/babel__traverse": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", - "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "node_modules/@tufjs/models": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-2.0.1.tgz", + "integrity": "sha512-92F7/SFyufn4DXsha9+QfKnN03JGqtMFMXgSHbZOo8JG59WkTni7UzAouNQDf7AuP9OAMxVOPQcqG3sB7w+kkg==", "dev": true, "dependencies": { - "@babel/types": "^7.20.7" + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, "node_modules/@types/body-parser": { @@ -5073,6 +5224,12 @@ "@types/node": "*" } }, + "node_modules/@types/chroma-js": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/chroma-js/-/chroma-js-2.4.4.tgz", + "integrity": "sha512-/DTccpHTaKomqussrn+ciEvfW4k6NAHzNzs/sts1TCqg333qNxOhy8TNIoQCmbGG3Tl8KdEhkGAssb1n3mTXiQ==", + "dev": true + }, "node_modules/@types/connect": { "version": "3.4.38", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", @@ -5092,10 +5249,31 @@ "@types/node": "*" } }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "dev": true + }, + "node_modules/@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/crypto-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.2.tgz", + "integrity": "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==", + "dev": true + }, "node_modules/@types/eslint": { - "version": "8.56.10", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", - "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", + "version": "8.56.5", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.5.tgz", + "integrity": "sha512-u5/YPJHo1tvkSF2CE0USEkxon82Z5DBy2xR+qfyYNszpX9qcs4sT6uq2kBbj4BXY1+DBGDPnrhMZV3pKWGNukw==", "dev": true, "dependencies": { "@types/estree": "*", @@ -5113,9 +5291,9 @@ } }, "node_modules/@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, "node_modules/@types/express": { @@ -5131,9 +5309,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.19.5", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", - "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.1.tgz", + "integrity": "sha512-ej0phymbFLoCB26dbbq5PGScsf2JAJ4IJHjG10LalgUV36XKTmA4GdA+PVllKvRk0sEKt64X8975qFnkSi0hqA==", "dev": true, "dependencies": { "@types/node": "*", @@ -5142,13 +5320,14 @@ "@types/send": "*" } }, - "node_modules/@types/graceful-fs": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", - "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "node_modules/@types/highlight.js": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-10.1.0.tgz", + "integrity": "sha512-77hF2dGBsOgnvZll1vymYiNUtqJ8cJfXPD6GG/2M0aLRc29PkvB7Au6sIDjIEFcSICBhCh2+Pyq6WSRS7LUm6A==", + "deprecated": "This is a stub types definition. highlight.js provides its own type definitions, so you do not need this installed.", "dev": true, "dependencies": { - "@types/node": "*" + "highlight.js": "*" } }, "node_modules/@types/http-errors": { @@ -5166,73 +5345,38 @@ "@types/node": "*" } }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "node_modules/@types/jasmine": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-5.1.4.tgz", + "integrity": "sha512-px7OMFO/ncXxixDe1zR13V1iycqWae0MxTaw62RpFlksUi5QuNWgQJFkTQjIOvrmutJbI7Fp2Y2N1F6D2R4G6w==", "dev": true }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/jest": { - "version": "28.1.8", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-28.1.8.tgz", - "integrity": "sha512-8TJkV++s7B6XqnDrzR1m/TT0A0h948Pnl/097veySPN67VRAgQ4gZ7n2KfJo2rVq6njQjdxU3GCCyDvAeuHoiw==", - "dev": true, - "dependencies": { - "expect": "^28.0.0", - "pretty-format": "^28.0.0" - } - }, - "node_modules/@types/jsdom": { - "version": "16.2.15", - "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-16.2.15.tgz", - "integrity": "sha512-nwF87yjBKuX/roqGYerZZM0Nv1pZDMAT5YhOHYeM/72Fic+VEqJh4nyoqoapzJnW3pUlfxPY5FhgsJtM+dRnQQ==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/parse5": "^6.0.3", - "@types/tough-cookie": "*" - } - }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, "node_modules/@types/lodash": { - "version": "4.17.6", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.6.tgz", - "integrity": "sha512-OpXEVoCKSS3lQqjx9GGGOapBeuW5eUboYHRlHP9urXPX25IKZ6AnP5ZRxtVf63iieUbsHxLn8NQ5Nlftc6yzAA==", + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha512-wYCP26ZLxaT3R39kiN2+HcJ4kTd3U1waI/cY7ivWYqFP6pW3ZNpvi6Wd6PHZx7T/t8z0vlkXMg3QYLa7DZ/IJQ==", "dev": true }, - "node_modules/@types/marked": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.3.2.tgz", - "integrity": "sha512-a79Yc3TOk6dGdituy8hmTTJXjOkZ7zsFYV10L337ttq/rec8lRMDBpV7fL3uLx6TgbFCa5DU/h8FmIBQPSbU0w==" + "node_modules/@types/lodash-es": { + "version": "4.17.12", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz", + "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", + "dev": true, + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/luxon": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.4.2.tgz", + "integrity": "sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==", + "dev": true }, "node_modules/@types/mime": { "version": "1.3.5", @@ -5240,17 +5384,14 @@ "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", "dev": true }, - "node_modules/@types/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", - "dev": true - }, "node_modules/@types/node": { - "version": "14.18.63", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", - "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", - "dev": true + "version": "20.11.25", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.25.tgz", + "integrity": "sha512-TBHyJxk2b7HceLVGFcpAUjsa5zIdsPWlR6XHfyGzd0SFu+/NFgQgMAl96MSDZgQDvJAvV6BKsFOrt6zIL09JDw==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } }, "node_modules/@types/node-forge": { "version": "1.3.11", @@ -5261,30 +5402,6 @@ "@types/node": "*" } }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", - "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", - "dev": true - }, - "node_modules/@types/parse-json": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", - "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", - "dev": true - }, - "node_modules/@types/parse5": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.3.tgz", - "integrity": "sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==", - "dev": true - }, - "node_modules/@types/prettier": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", - "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", - "dev": true - }, "node_modules/@types/qs": { "version": "6.9.15", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", @@ -5298,9 +5415,9 @@ "dev": true }, "node_modules/@types/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", "dev": true }, "node_modules/@types/send": { @@ -5333,18 +5450,6 @@ "@types/send": "*" } }, - "node_modules/@types/sinonjs__fake-timers": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz", - "integrity": "sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==", - "dev": true - }, - "node_modules/@types/sizzle": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.8.tgz", - "integrity": "sha512-0vWLNK2D5MT9dg0iOo8GlKguPAU02QjmZitPEsXRuJXU/OGIOt9vT9Fc26wtYuavLxtO45v9PGleoL9Z0k1LHg==", - "dev": true - }, "node_modules/@types/sockjs": { "version": "0.3.36", "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", @@ -5354,78 +5459,41 @@ "@types/node": "*" } }, - "node_modules/@types/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true - }, - "node_modules/@types/tough-cookie": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", - "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", - "dev": true - }, "node_modules/@types/ws": { - "version": "8.5.11", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.11.tgz", - "integrity": "sha512-4+q7P5h3SpJxaBft0Dzpbr6lmMaqh0Jr2tbhJZ/luAwvD7ohSCniYkwz/pLxuT2h0EOa6QADgJj1Ko+TzRfZ+w==", + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", "dev": true, "dependencies": { "@types/node": "*" } }, - "node_modules/@types/yargs": { - "version": "17.0.32", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", - "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.2.0.tgz", + "integrity": "sha512-02tJIs655em7fvt9gps/+4k4OsKULYGtLBPJfOsmOq1+3cdClYiF0+d6mHu6qDnTcg88wJBkcPLpQhq7FyDz0A==", "dev": true, "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true - }, - "node_modules/@types/yauzl": { - "version": "2.10.3", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", - "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", - "dev": true, - "optional": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.34.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.34.0.tgz", - "integrity": "sha512-eRfPPcasO39iwjlUAMtjeueRGuIrW3TQ9WseIDl7i5UWuFbf83yYaU7YPs4j8+4CxUMIsj1k+4kV+E+G+6ypDQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.34.0", - "@typescript-eslint/type-utils": "5.34.0", - "@typescript-eslint/utils": "5.34.0", - "debug": "^4.3.4", - "functional-red-black-tree": "^1.0.1", - "ignore": "^5.2.0", - "regexpp": "^3.2.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/type-utils": "8.2.0", + "@typescript-eslint/utils": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -5433,25 +5501,57 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { - "version": "5.34.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.34.0.tgz", - "integrity": "sha512-Pxlno9bjsQ7hs1pdWRUv9aJijGYPYsHpwMeCQ/Inavhym3/XaKt1ZKAA8FIw4odTBfowBdZJDMxf2aavyMDkLg==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.2.0.tgz", + "integrity": "sha512-OFn80B38yD6WwpoHU2Tz/fTz7CgFqInllBoC3WP+/jLbTb4gGPTy9HBSTsbDWkMdN55XlVU0mMDYAtgvlUspGw==", "dev": true, "dependencies": { - "@typescript-eslint/utils": "5.34.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.2.0.tgz", + "integrity": "sha512-6a9QSK396YqmiBKPkJtxsgZZZVjYQ6wQ/TlI0C65z7vInaETuC6HAHD98AGLC8DyIPqHytvNuS8bBVvNLKyqvQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.2.0.tgz", + "integrity": "sha512-kiG4EDUT4dImplOsbh47B1QnNmXSoUqOjWDvCJw/o8LgfD0yr7k2uy54D5Wm0j4t71Ge1NkynGhpWdS0dEIAUA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, - "peerDependencies": { - "eslint": "*" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, "peerDependenciesMeta": { "typescript": { @@ -5460,49 +5560,94 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "5.34.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.34.0.tgz", - "integrity": "sha512-kWRYybU4Rn++7lm9yu8pbuydRyQsHRoBDIo11k7eqBWTldN4xUdVUMCsHBiE7aoEkFzrUEaZy3iH477vr4xHAQ==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.2.0.tgz", + "integrity": "sha512-O46eaYKDlV3TvAVDNcoDzd5N550ckSe8G4phko++OCSC1dYIb9LTc3HDGYdWqWIAT5qDUKphO6sd9RrpIJJPfg==", "dev": true, "dependencies": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.34.0", - "@typescript-eslint/types": "5.34.0", - "@typescript-eslint/typescript-estree": "5.34.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/typescript-estree": "8.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^8.57.0 || ^9.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.2.0.tgz", + "integrity": "sha512-sbgsPMW9yLvS7IhCi8IpuK1oBmtbWUNP+hBdwl/I9nzqVsszGnNGti5r9dUtF5RLivHUFFIdRvLiTsPhzSyJ3Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.2.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" } }, "node_modules/@typescript-eslint/parser": { - "version": "5.34.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.34.0.tgz", - "integrity": "sha512-SZ3NEnK4usd2CXkoV3jPa/vo1mWX1fqRyIVUQZR4As1vyp4fneknBNJj+OFtV8WAVgGf+rOHMSqQbs2Qn3nFZQ==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.2.0.tgz", + "integrity": "sha512-j3Di+o0lHgPrb7FxL3fdEy6LJ/j2NE8u+AP/5cQ9SKb+JLH6V6UHDqJ+e0hXBkHP1wn1YDFjYCS9LBQsZDlDEg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.34.0", - "@typescript-eslint/types": "5.34.0", - "@typescript-eslint/typescript-estree": "5.34.0", + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/typescript-estree": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", "debug": "^4.3.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^8.57.0 || ^9.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -5510,79 +5655,141 @@ } } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.34.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.34.0.tgz", - "integrity": "sha512-HNvASMQlah5RsBW6L6c7IJ0vsm+8Sope/wu5sEAf7joJYWNb1LDbJipzmdhdUOnfrDFE6LR1j57x1EYVxrY4ow==", + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.2.0.tgz", + "integrity": "sha512-OFn80B38yD6WwpoHU2Tz/fTz7CgFqInllBoC3WP+/jLbTb4gGPTy9HBSTsbDWkMdN55XlVU0mMDYAtgvlUspGw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.34.0", - "@typescript-eslint/visitor-keys": "5.34.0" + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.36.2.tgz", - "integrity": "sha512-rPQtS5rfijUWLouhy6UmyNquKDPhQjKsaKH0WnY6hl/07lasj8gPaH2UD8xWkePn6SC+jW2i9c2DZVDnL+Dokw==", + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.2.0.tgz", + "integrity": "sha512-6a9QSK396YqmiBKPkJtxsgZZZVjYQ6wQ/TlI0C65z7vInaETuC6HAHD98AGLC8DyIPqHytvNuS8bBVvNLKyqvQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.2.0.tgz", + "integrity": "sha512-kiG4EDUT4dImplOsbh47B1QnNmXSoUqOjWDvCJw/o8LgfD0yr7k2uy54D5Wm0j4t71Ge1NkynGhpWdS0dEIAUA==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.36.2", - "@typescript-eslint/utils": "5.36.2", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", "debug": "^4.3.4", - "tsutils": "^3.21.0" + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependencies": { - "eslint": "*" - }, "peerDependenciesMeta": { "typescript": { "optional": true } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.36.2.tgz", - "integrity": "sha512-9OJSvvwuF1L5eS2EQgFUbECb99F0mwq501w0H0EkYULkhFa19Qq7WFbycdw1PexAc929asupbZcgjVIe6OK/XQ==", + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.2.0.tgz", + "integrity": "sha512-sbgsPMW9yLvS7IhCi8IpuK1oBmtbWUNP+hBdwl/I9nzqVsszGnNGti5r9dUtF5RLivHUFFIdRvLiTsPhzSyJ3Q==", "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.2.0", + "eslint-visitor-keys": "^3.4.3" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.36.2.tgz", - "integrity": "sha512-8fyH+RfbKc0mTspfuEjlfqA4YywcwQK2Amcf6TDOwaRLg7Vwdu4bZzyvBZp4bjt1RRjQ5MDnOZahxMrt2l5v9w==", + "node_modules/@typescript-eslint/parser/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.10.0.tgz", + "integrity": "sha512-AgCaEjhfql9MDKjMUxWvH7HjLeBqMCBfIaBbzzIcBbQPZE7CPh1m6FF+L75NUMJFMLYhCywJXIDEMa3//1A0dw==", + "dev": true, + "peer": true, + "dependencies": { + "@typescript-eslint/types": "8.10.0", + "@typescript-eslint/visitor-keys": "8.10.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.2.0.tgz", + "integrity": "sha512-g1CfXGFMQdT5S+0PSO0fvGXUaiSkl73U1n9LTK5aRAFnPlJ8dLKkXr4AaLFvPedW8lVDoMgLLE3JN98ZZfsj0w==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/visitor-keys": "5.36.2", + "@typescript-eslint/typescript-estree": "8.2.0", + "@typescript-eslint/utils": "8.2.0", "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -5594,52 +5801,53 @@ } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.36.2.tgz", - "integrity": "sha512-BtRvSR6dEdrNt7Net2/XDjbYKU5Ml6GqJgVfXT0CxTCJlnIqK7rAGreuWKMT2t8cFUT2Msv5oxw0GMRD7T5J7A==", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/scope-manager": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.2.0.tgz", + "integrity": "sha512-OFn80B38yD6WwpoHU2Tz/fTz7CgFqInllBoC3WP+/jLbTb4gGPTy9HBSTsbDWkMdN55XlVU0mMDYAtgvlUspGw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.36.2", - "eslint-visitor-keys": "^3.3.0" + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/types": { - "version": "5.34.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.34.0.tgz", - "integrity": "sha512-49fm3xbbUPuzBIOcy2CDpYWqy/X7VBkxVN+DC21e0zIm3+61Z0NZi6J9mqPmSW1BDVk9FIOvuCFyUPjXz93sjA==", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.2.0.tgz", + "integrity": "sha512-6a9QSK396YqmiBKPkJtxsgZZZVjYQ6wQ/TlI0C65z7vInaETuC6HAHD98AGLC8DyIPqHytvNuS8bBVvNLKyqvQ==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.34.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.34.0.tgz", - "integrity": "sha512-mXHAqapJJDVzxauEkfJI96j3D10sd567LlqroyCeJaHnu42sDbjxotGb3XFtGPYKPD9IyLjhsoULML1oI3M86A==", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.2.0.tgz", + "integrity": "sha512-kiG4EDUT4dImplOsbh47B1QnNmXSoUqOjWDvCJw/o8LgfD0yr7k2uy54D5Wm0j4t71Ge1NkynGhpWdS0dEIAUA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.34.0", - "@typescript-eslint/visitor-keys": "5.34.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -5651,76 +5859,106 @@ } } }, - "node_modules/@typescript-eslint/utils": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.36.2.tgz", - "integrity": "sha512-uNcopWonEITX96v9pefk9DC1bWMdkweeSsewJ6GeC7L6j2t0SJywisgkr9wUTtXk90fi2Eljj90HSHm3OGdGRg==", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.2.0.tgz", + "integrity": "sha512-O46eaYKDlV3TvAVDNcoDzd5N550ckSe8G4phko++OCSC1dYIb9LTc3HDGYdWqWIAT5qDUKphO6sd9RrpIJJPfg==", "dev": true, "dependencies": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.36.2", - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/typescript-estree": "5.36.2", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/typescript-estree": "8.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^8.57.0 || ^9.0.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.36.2.tgz", - "integrity": "sha512-cNNP51L8SkIFSfce8B1NSUBTJTu2Ts4nWeWbFrdaqjmn9yKrAaJUBHkyTZc0cL06OFHpb+JZq5AUHROS398Orw==", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.2.0.tgz", + "integrity": "sha512-sbgsPMW9yLvS7IhCi8IpuK1oBmtbWUNP+hBdwl/I9nzqVsszGnNGti5r9dUtF5RLivHUFFIdRvLiTsPhzSyJ3Q==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/visitor-keys": "5.36.2" + "@typescript-eslint/types": "8.2.0", + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.36.2.tgz", - "integrity": "sha512-9OJSvvwuF1L5eS2EQgFUbECb99F0mwq501w0H0EkYULkhFa19Qq7WFbycdw1PexAc929asupbZcgjVIe6OK/XQ==", + "node_modules/@typescript-eslint/type-utils/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.10.0.tgz", + "integrity": "sha512-k/E48uzsfJCRRbGLapdZgrX52csmWJ2rcowwPvOZ8lwPUv3xW6CcFeJAXgx4uJm+Ge4+a4tFOkdYvSpxhRhg1w==", "dev": true, + "peer": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.36.2.tgz", - "integrity": "sha512-8fyH+RfbKc0mTspfuEjlfqA4YywcwQK2Amcf6TDOwaRLg7Vwdu4bZzyvBZp4bjt1RRjQ5MDnOZahxMrt2l5v9w==", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.10.0.tgz", + "integrity": "sha512-3OE0nlcOHaMvQ8Xu5gAfME3/tWVDpb/HxtpUZ1WeOAksZ/h/gwrBzCklaGzwZT97/lBbbxJ16dMA98JMEngW4w==", "dev": true, + "peer": true, "dependencies": { - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/visitor-keys": "5.36.2", + "@typescript-eslint/types": "8.10.0", + "@typescript-eslint/visitor-keys": "8.10.0", "debug": "^4.3.4", - "globby": "^11.1.0", + "fast-glob": "^3.3.2", "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -5732,189 +5970,202 @@ } } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.36.2.tgz", - "integrity": "sha512-BtRvSR6dEdrNt7Net2/XDjbYKU5Ml6GqJgVfXT0CxTCJlnIqK7rAGreuWKMT2t8cFUT2Msv5oxw0GMRD7T5J7A==", + "node_modules/@typescript-eslint/utils": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.10.0.tgz", + "integrity": "sha512-Oq4uZ7JFr9d1ZunE/QKy5egcDRXT/FrS2z/nlxzPua2VHFtmMvFNDvpq1m/hq0ra+T52aUezfcjGRIB7vNJF9w==", "dev": true, + "peer": true, "dependencies": { - "@typescript-eslint/types": "5.36.2", - "eslint-visitor-keys": "^3.3.0" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.10.0", + "@typescript-eslint/types": "8.10.0", + "@typescript-eslint/typescript-estree": "8.10.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.34.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.34.0.tgz", - "integrity": "sha512-O1moYjOSrab0a2fUvFpsJe0QHtvTC+cR+ovYpgKrAVXzqQyc74mv76TgY6z+aEtjQE2vgZux3CQVtGryqdcOAw==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.10.0.tgz", + "integrity": "sha512-k8nekgqwr7FadWk548Lfph6V3r9OVqjzAIVskE7orMZR23cGJjAOVazsZSJW+ElyjfTM4wx/1g88Mi70DDtG9A==", "dev": true, + "peer": true, "dependencies": { - "@typescript-eslint/types": "5.34.0", - "eslint-visitor-keys": "^3.3.0" + "@typescript-eslint/types": "8.10.0", + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true + "node_modules/@vitejs/plugin-basic-ssl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.1.0.tgz", + "integrity": "sha512-wO4Dk/rm8u7RNhOf95ZzcEmC9rYOncYgvq4z3duaJrCgjN8BxAnDVyndanfcJZ0O6XZzHz6Q0hTimxTg8Y9g/A==", + "dev": true, + "engines": { + "node": ">=14.6.0" + }, + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" + } }, "node_modules/@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", "dev": true, "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" } }, "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", "dev": true }, "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", "dev": true }, "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", "dev": true }, "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", "dev": true, "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", "dev": true }, "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" } }, "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", "dev": true, "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "node_modules/@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", "dev": true, "dependencies": { "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", "dev": true }, "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" } }, "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" } }, "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/ast": "1.12.1", "@xtuc/long": "4.2.2" } }, @@ -5936,50 +6187,20 @@ "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", "dev": true }, - "node_modules/@yarnpkg/parsers": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@yarnpkg/parsers/-/parsers-3.0.2.tgz", - "integrity": "sha512-/HcYgtUSiJiot/XWGLOlGxPYUG65+/31V8oqk17vZLW1xlCoR4PampyePljOxY2n8/3jz9+tIFzICsyGujJZoA==", - "dev": true, - "dependencies": { - "js-yaml": "^3.10.0", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=18.12.0" - } + "node_modules/@yr/monotone-cubic-spline": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@yr/monotone-cubic-spline/-/monotone-cubic-spline-1.0.3.tgz", + "integrity": "sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA==" }, - "node_modules/@zkochan/js-yaml": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/@zkochan/js-yaml/-/js-yaml-0.0.6.tgz", - "integrity": "sha512-nzvgl3VfhcELQ8LyVrYOru+UtAy1nrygk2+AGbTm8a5YcO6o8lSjAT+pfg3vJWxIoZKOUhrK6UU7xW/+00kQrg==", + "node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/@zkochan/js-yaml/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/abab": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "deprecated": "Use your platform's native atob() and btoa() methods instead", - "dev": true - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -5993,39 +6214,11 @@ "node": ">= 0.6" } }, - "node_modules/ace-builds": { - "version": "1.35.2", - "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.35.2.tgz", - "integrity": "sha512-06d00u4jDZx+ieI0jLlgy/uefx8kcgz7lhI0mCIFEu8NVWirH00U5IEP7tePHy4sjPsRcJUH4VbJZacoit2Hng==", - "dev": true - }, "node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, - "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - } - }, - "node_modules/acorn-globals/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.13.0.tgz", + "integrity": "sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==", + "devOptional": true, "bin": { "acorn": "bin/acorn" }, @@ -6051,15 +6244,6 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/adjust-sourcemap-loader": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", @@ -6088,27 +6272,15 @@ } }, "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", "dev": true, "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/agentkeepalive": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", - "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", - "dev": true, - "dependencies": { - "humanize-ms": "^1.2.1" + "debug": "^4.3.4" }, "engines": { - "node": ">= 8.0.0" + "node": ">= 14" } }, "node_modules/aggregate-error": { @@ -6125,15 +6297,15 @@ } }, "node_modules/ajv": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", - "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", + "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.1", + "fast-deep-equal": "^3.1.3", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "uri-js": "^4.4.1" }, "funding": { "type": "github", @@ -6169,13 +6341,22 @@ "ajv": "^8.8.2" } }, - "node_modules/ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "node_modules/angular-eslint": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/angular-eslint/-/angular-eslint-18.3.1.tgz", + "integrity": "sha512-p3/1DfH8TpsMHUDMLECn6/1uPcHjd7/0tL8prXZuO93mZFV4Y+P9MBwLheA14tw8UXbnKWXW8SZz9hov6PaLRw==", "dev": true, "dependencies": { - "string-width": "^4.1.0" + "@angular-eslint/builder": "18.3.1", + "@angular-eslint/eslint-plugin": "18.3.1", + "@angular-eslint/eslint-plugin-template": "18.3.1", + "@angular-eslint/schematics": "18.3.1", + "@angular-eslint/template-parser": "18.3.1" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*", + "typescript-eslint": "^8.0.0" } }, "node_modules/ansi-colors": { @@ -6202,18 +6383,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/ansi-html-community": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", @@ -6245,10 +6414,17 @@ "node": ">=4" } }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -6257,65 +6433,36 @@ "node": ">= 8" } }, - "node_modules/append-field": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", - "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", - "dev": true - }, - "node_modules/aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "dev": true - }, - "node_modules/arch": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", - "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/are-docs-informative": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", - "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "engines": { - "node": ">=14" + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/are-we-there-yet": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", - "deprecated": "This package is no longer supported.", - "dev": true, + "node_modules/apexcharts": { + "version": "3.54.1", + "resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-3.54.1.tgz", + "integrity": "sha512-E4et0h/J1U3r3EwS/WlqJCQIbepKbp6wGUmaAwJOMjHUP4Ci0gxanLa7FR3okx6p9coi4st6J853/Cb1NP0vpA==", "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "@yr/monotone-cubic-spline": "^1.0.3", + "svg.draggable.js": "^2.2.2", + "svg.easing.js": "^2.0.0", + "svg.filter.js": "^2.0.2", + "svg.pathmorphing.js": "^0.1.3", + "svg.resize.js": "^1.4.3", + "svg.select.js": "^3.0.1" } }, "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", "dev": true }, "node_modules/argparse": { @@ -6328,28 +6475,12 @@ } }, "node_modules/aria-query": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.2.tgz", - "integrity": "sha512-eigU3vhqSO+Z8BKDnVLN/ompjhf3pYzecKXz8+whRy+9gZu8n1TCGfwzQUUPnqdHl9ax1Hr9031orZ+UOEYr7Q==", - "dev": true, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "dequal": "^2.0.3" } }, "node_modules/array-flatten": { @@ -6358,26 +6489,6 @@ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", "dev": true }, - "node_modules/array-includes": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", - "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.4", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -6387,165 +6498,6 @@ "node": ">=8" } }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", - "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", - "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.2.1", - "get-intrinsic": "^1.2.3", - "is-array-buffer": "^3.0.4", - "is-shared-array-buffer": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dev": true - }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/assert-never": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.3.0.tgz", - "integrity": "sha512-9Z3vxQ+berkL/JJo0dK+EY3Lp0s3NtSnP3VCLsh5HDcZPrh0M+KQRK5sWhUeyPPH+/RCxZqOxLMR+YC6vlviEQ==", - "dev": true - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", - "dev": true - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true, - "bin": { - "atob": "bin/atob.js" - }, - "engines": { - "node": ">= 4.5.0" - } - }, "node_modules/autoprefixer": { "version": "10.4.19", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", @@ -6583,328 +6535,94 @@ "postcss": "^8.1.0" } }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", "dev": true, - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "node_modules/babel-loader": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", + "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", "dev": true, + "dependencies": { + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" + }, "engines": { - "node": "*" + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" } }, - "node_modules/aws4": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.0.tgz", - "integrity": "sha512-3AungXC4I8kKsS9PuS4JH2nc+0bVY/mjgrephHTIi8fpEeGsTHBUJeosp0Wc1myYMElmD0B3Oc4XL/HVJ4PV2g==", - "dev": true - }, - "node_modules/axios": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", - "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/axios/node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", + "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", "dev": true, "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.2", + "semver": "^6.3.1" }, - "engines": { - "node": ">= 6" + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/axios/node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true - }, - "node_modules/axobject-query": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.0.1.tgz", - "integrity": "sha512-vy5JPSOibF9yAeC2PoemRdA1MuSXX7vX5osdoxKf/6OUeppAWekZ3JIJVNWFMH6wgj7uHYyqZUSqE/b/3JLV1A==", + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "engines": { - "node": ">=6.0" + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/babel-jest": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.3.tgz", - "integrity": "sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q==", + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz", + "integrity": "sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==", "dev": true, "dependencies": { - "@jest/transform": "^28.1.3", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^28.1.3", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "@babel/helper-define-polyfill-provider": "^0.6.1", + "core-js-compat": "^3.36.1" }, "peerDependencies": { - "@babel/core": "^7.8.0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/babel-jest/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", + "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" + "@babel/helper-define-polyfill-provider": "^0.6.2" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/babel-jest/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/babel-jest/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/babel-jest/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/babel-jest/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-jest/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-loader": { - "version": "8.2.5", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", - "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", - "dev": true, - "dependencies": { - "find-cache-dir": "^3.3.1", - "loader-utils": "^2.0.0", - "make-dir": "^3.1.0", - "schema-utils": "^2.6.5" - }, - "engines": { - "node": ">= 8.9" - }, - "peerDependencies": { - "@babel/core": "^7.0.0", - "webpack": ">=2" - } - }, - "node_modules/babel-loader/node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.3.tgz", - "integrity": "sha512-Ys3tUKAmfnkRUpPdpa98eYrAR0nV+sSFUZZEGuQ2EbFd1y4SOLtD5QDNHAq+bb9a+bbXvYQC4b+ID/THIMcU6Q==", - "dev": true, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", - "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.3", - "semver": "^6.1.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz", - "integrity": "sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.2", - "core-js-compat": "^3.21.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-preset-jest": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.1.3.tgz", - "integrity": "sha512-L+fupJvlWAHbQfn74coNX3zf60LXMJsezNvvx8eIh7iOR1luJ1poxYgQk1F8PYtNq/6QODDHCqsSnTFSWC491A==", - "dev": true, - "dependencies": { - "babel-plugin-jest-hoist": "^28.1.3", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-walk": { - "version": "3.0.0-canary-5", - "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz", - "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.9.6" - }, - "engines": { - "node": ">= 10.0.0" + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/balanced-match": { @@ -6916,7 +6634,6 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, "funding": [ { "type": "github", @@ -6932,21 +6649,21 @@ } ] }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "dev": true, + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, "node_modules/batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", "dev": true }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dev": true, - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, "node_modules/big.js": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", @@ -6957,39 +6674,24 @@ } }, "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, - "node_modules/blob-util": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", - "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==", - "dev": true - }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, "node_modules/body-parser": { "version": "1.20.2", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", @@ -7023,39 +6725,12 @@ "ms": "2.0.0" } }, - "node_modules/body-parser/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "node_modules/body-parser/node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/bonjour-service": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", @@ -7072,158 +6747,50 @@ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "dev": true }, - "node_modules/boxen": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", - "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", - "dev": true, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dependencies": { - "ansi-align": "^3.0.0", - "camelcase": "^6.2.0", - "chalk": "^4.1.0", - "cli-boxes": "^2.2.1", - "string-width": "^4.2.2", - "type-fest": "^0.20.2", - "widest-line": "^3.1.0", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "balanced-match": "^1.0.0" } }, - "node_modules/boxen/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "fill-range": "^7.0.1" }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/boxen/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "node_modules/browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/boxen/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/boxen/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/boxen/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/boxen/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/boxen/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, - "node_modules/browserslist": { - "version": "4.23.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", - "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001640", - "electron-to-chromium": "^1.4.820", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.1.0" + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" }, "bin": { "browserslist": "cli.js" @@ -7232,32 +6799,10 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "dependencies": { - "node-int64": "^0.4.0" - } - }, "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, "funding": [ { "type": "github", @@ -7277,67 +6822,27 @@ "ieee754": "^1.1.13" } }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "node_modules/builtins": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.1.0.tgz", - "integrity": "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==", - "dev": true, - "dependencies": { - "semver": "^7.0.0" - } - }, - "node_modules/busboy": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", - "integrity": "sha512-InWFDomvlkEj+xWLBfU3AvnbVYqeTWmQopiW0tWWEy5yehYm2YkGEc59sUmw/4ty5Zj/b0WHGs1LgecuBSBGrg==", + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", "dev": true, "dependencies": { - "dicer": "0.2.5", - "readable-stream": "1.1.x" + "run-applescript": "^7.0.0" }, "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/busboy/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "node_modules/busboy/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/busboy/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -7348,50 +6853,35 @@ } }, "node_modules/cacache": { - "version": "16.1.1", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.1.tgz", - "integrity": "sha512-VDKN+LHyCQXaaYZ7rA/qtkURU+/yYhviUdvqEv2LT6QPZU8jpyzEkEVAcKlKLt5dJ5BRp11ym8lo3NKLluEPLg==", + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.3.tgz", + "integrity": "sha512-qXCd4rh6I07cnDqh8V48/94Tc/WSfj+o3Gn6NZ0aZovS255bUx8O13uKxRFd2eWG0xgsco7+YItQNPaa5E85hg==", "dev": true, "dependencies": { - "@npmcli/fs": "^2.1.0", - "@npmcli/move-file": "^2.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "glob": "^8.0.1", - "infer-owner": "^1.0.4", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", + "ssri": "^10.0.0", "tar": "^6.1.11", - "unique-filename": "^1.1.1" + "unique-filename": "^3.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^16.14.0 || >=18.0.0" } }, "node_modules/cacache/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/cachedir": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.4.0.tgz", - "integrity": "sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", "dev": true, "engines": { - "node": ">=6" + "node": "14 || >=16.14" } }, "node_modules/call-bind": { @@ -7417,7 +6907,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, "engines": { "node": ">=6" } @@ -7431,27 +6920,20 @@ "node": ">=6" } }, - "node_modules/camelcase-keys": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", - "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "map-obj": "^4.0.0", - "quick-lru": "^4.0.1" - }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 6" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001642", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz", - "integrity": "sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==", + "version": "1.0.30001621", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001621.tgz", + "integrity": "sha512-+NLXZiviFFKX0fk8Piwv3PfLPGtRqJeq2TiNoUff/qB5KJgwecJTvCXDpmlyP/eCI/GUEmp/h/y5j0yckiiZrA==", + "dev": true, "funding": [ { "type": "opencollective", @@ -7467,12 +6949,6 @@ } ] }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true - }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -7486,43 +6962,43 @@ "node": ">=4" } }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/character-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", - "integrity": "sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==", - "dev": true, - "dependencies": { - "is-regex": "^1.0.3" - } - }, "node_modules/chardet": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, - "node_modules/check-more-types": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", - "integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==", - "dev": true, - "engines": { - "node": ">= 0.8.0" + "node_modules/chevrotain": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz", + "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==", + "optional": true, + "dependencies": { + "@chevrotain/cst-dts-gen": "11.0.3", + "@chevrotain/gast": "11.0.3", + "@chevrotain/regexp-to-ast": "11.0.3", + "@chevrotain/types": "11.0.3", + "@chevrotain/utils": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/chevrotain-allstar": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz", + "integrity": "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==", + "optional": true, + "dependencies": { + "lodash-es": "^4.17.21" + }, + "peerDependencies": { + "chevrotain": "^11.0.0" } }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -7551,36 +7027,21 @@ "node": ">=10" } }, + "node_modules/chroma-js": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.4.2.tgz", + "integrity": "sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A==", + "dev": true + }, "node_modules/chrome-trace-event": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", - "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", "dev": true, "engines": { "node": ">=6.0" } }, - "node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, - "node_modules/cjs-module-lexer": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz", - "integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==", - "dev": true - }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -7590,23 +7051,10 @@ "node": ">=6" } }, - "node_modules/cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, "dependencies": { "restore-cursor": "^3.1.0" }, @@ -7615,10 +7063,9 @@ } }, "node_modules/cli-spinners": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", - "dev": true, + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", "engines": { "node": ">=6" }, @@ -7626,50 +7073,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cli-table3": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", - "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0" - }, - "engines": { - "node": "10.* || >= 12.*" - }, - "optionalDependencies": { - "@colors/colors": "1.5.0" - } - }, - "node_modules/cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", - "dev": true, - "dependencies": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", "dev": true, "engines": { - "node": ">= 10" + "node": ">= 12" } }, "node_modules/clipboard": { "version": "2.0.11", "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz", "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==", + "optional": true, "dependencies": { "good-listener": "^1.2.2", "select": "^1.1.2", @@ -7677,65 +7094,85 @@ } }, "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dependencies": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" - } - }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true, + }, "engines": { - "node": ">=0.8" + "node": ">=12" } }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=6" - } - }, - "node_modules/clone-deep/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "isobject": "^3.0.1" + "color-name": "~1.1.4" }, "engines": { - "node": ">=0.10.0" + "node": ">=7.0.0" } }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, + "node_modules/cliui/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" + "node": ">=0.8" } }, - "node_modules/collect-v8-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", - "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", - "dev": true + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } }, "node_modules/color-convert": { "version": "1.9.3", @@ -7750,70 +7187,25 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true, - "bin": { - "color-support": "bin.js" - } - }, - "node_modules/colord": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", - "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", - "dev": true - }, "node_modules/colorette": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", - "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "dev": true }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/commander": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", "dev": true, "engines": { "node": ">= 6" } }, - "node_modules/comment-parser": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", - "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", - "dev": true, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/common-tags": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", - "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", "dev": true }, "node_modules/compressible": { @@ -7882,55 +7274,25 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "engines": [ - "node >= 0.8" - ], - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/concat-stream/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "node_modules/concat-stream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/concat-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "optional": true }, - "node_modules/concat-stream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", "dev": true, "dependencies": { - "safe-buffer": "~5.1.0" + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" } }, "node_modules/connect-history-api-fallback": { @@ -7942,26 +7304,26 @@ "node": ">=0.8" } }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "dev": true - }, - "node_modules/constantinople": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", - "integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==", + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "dependencies": { - "@babel/parser": "^7.6.0", - "@babel/types": "^7.6.1" + "ms": "2.0.0" } }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, "dependencies": { "safe-buffer": "5.2.1" }, @@ -7981,12 +7343,13 @@ "node_modules/convert-source-map": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", "dev": true, "engines": { "node": ">= 0.6" @@ -8046,65 +7409,6 @@ "node": ">=10.13.0" } }, - "node_modules/copy-webpack-plugin/node_modules/globby": { - "version": "13.2.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", - "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", - "dev": true, - "dependencies": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.3.0", - "ignore": "^5.2.4", - "merge2": "^1.4.1", - "slash": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/copy-webpack-plugin/node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/copy-webpack-plugin/node_modules/schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/copy-webpack-plugin/node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/core-js-compat": { "version": "3.37.1", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", @@ -8119,53 +7423,87 @@ } }, "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/cose-base": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", + "optional": true, "dependencies": { "layout-base": "^1.0.0" } }, "node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", - "dev": true, + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true + "node_modules/cosmiconfig/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/cosmiconfig/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } }, "node_modules/critters": { - "version": "0.0.16", - "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.16.tgz", - "integrity": "sha512-JwjgmO6i3y6RWtLYmXwO5jMd+maZt8Tnfu7VVISmEWyQqfLpB8soBswf8/2bu6SBXxtKA68Al3c+qIG1ApT68A==", + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.22.tgz", + "integrity": "sha512-NU7DEcQZM2Dy8XTKFHxtdnIM/drE312j2T4PCVaSUcS0oBeyT/NImpRw/Ap0zOr/1SE7SgPK9tGPg1WK/sVakw==", "dev": true, "dependencies": { "chalk": "^4.1.0", - "css-select": "^4.2.0", - "parse5": "^6.0.1", - "parse5-htmlparser2-tree-adapter": "^6.0.1", - "postcss": "^8.3.7", - "pretty-bytes": "^5.3.0" + "css-select": "^5.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.2", + "htmlparser2": "^8.0.2", + "postcss": "^8.4.23", + "postcss-media-query-parser": "^0.2.3" } }, "node_modules/critters/node_modules/ansi-styles": { @@ -8226,12 +7564,6 @@ "node": ">=8" } }, - "node_modules/critters/node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, "node_modules/critters/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -8257,113 +7589,56 @@ "node": ">= 8" } }, - "node_modules/css": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz", - "integrity": "sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==", - "dev": true, - "dependencies": { - "inherits": "^2.0.4", - "source-map": "^0.6.1", - "source-map-resolve": "^0.6.0" - } - }, - "node_modules/css-blank-pseudo": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz", - "integrity": "sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.9" - }, - "bin": { - "css-blank-pseudo": "dist/cli.cjs" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/css-functions-list": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.2.tgz", - "integrity": "sha512-c+N0v6wbKVxTu5gOBBFkr9BEdBWaqqjQeiJ8QvSRIJOf+UxlJh930m8e6/WNeODIK0mYLFkoONrnj16i2EcvfQ==", - "dev": true, - "engines": { - "node": ">=12 || >=16" - } - }, - "node_modules/css-has-pseudo": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz", - "integrity": "sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.9" - }, - "bin": { - "css-has-pseudo": "dist/cli.cjs" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/css-loader": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz", - "integrity": "sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw==", + "node_modules/crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" + }, + "node_modules/css-loader": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.1.tgz", + "integrity": "sha512-OxIR5P2mjO1PSXk44bWuQ8XtMK4dpEqpIyERCx3ewOo3I8EmbcxMPUc5ScLtQfgXtOojoMv57So4V/C02HQLsw==", "dev": true, "dependencies": { "icss-utils": "^5.1.0", - "postcss": "^8.4.7", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.0", - "postcss-modules-scope": "^3.0.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", "postcss-modules-values": "^4.0.0", "postcss-value-parser": "^4.2.0", - "semver": "^7.3.5" + "semver": "^7.5.4" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/css-prefers-color-scheme": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", - "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", - "dev": true, - "bin": { - "css-prefers-color-scheme": "dist/cli.cjs" - }, - "engines": { - "node": "^12 || ^14 || >=16" + "@rspack/core": "0.x || 1.x", + "webpack": "^5.27.0" }, - "peerDependencies": { - "postcss": "^8.4" + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } } }, "node_modules/css-select": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", - "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "dev": true, "dependencies": { "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", "nth-check": "^2.0.1" }, "funding": { @@ -8382,25 +7657,6 @@ "url": "https://github.com/sponsors/fb55" } }, - "node_modules/css/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cssdb": { - "version": "6.6.3", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-6.6.3.tgz", - "integrity": "sha512-7GDvDSmE+20+WcSMhP17Q1EVWUrLlbxxpMDqG731n8P99JhnQZHR9YvtjPvEHfjFUjvQJvdpKCjlKOX+xe4UVA==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -8413,191 +7669,17 @@ "node": ">=4" } }, - "node_modules/cssom": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", - "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", - "dev": true - }, - "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "dependencies": { - "cssom": "~0.3.6" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, - "node_modules/cypress": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-10.6.0.tgz", - "integrity": "sha512-6sOpHjostp8gcLO34p6r/Ci342lBs8S5z9/eb3ZCQ22w2cIhMWGUoGKkosabPBfKcvRS9BE4UxybBtlIs8gTQA==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "@cypress/request": "^2.88.10", - "@cypress/xvfb": "^1.2.4", - "@types/node": "^14.14.31", - "@types/sinonjs__fake-timers": "8.1.1", - "@types/sizzle": "^2.3.2", - "arch": "^2.2.0", - "blob-util": "^2.0.2", - "bluebird": "^3.7.2", - "buffer": "^5.6.0", - "cachedir": "^2.3.0", - "chalk": "^4.1.0", - "check-more-types": "^2.24.0", - "cli-cursor": "^3.1.0", - "cli-table3": "~0.6.1", - "commander": "^5.1.0", - "common-tags": "^1.8.0", - "dayjs": "^1.10.4", - "debug": "^4.3.2", - "enquirer": "^2.3.6", - "eventemitter2": "^6.4.3", - "execa": "4.1.0", - "executable": "^4.1.1", - "extract-zip": "2.0.1", - "figures": "^3.2.0", - "fs-extra": "^9.1.0", - "getos": "^3.2.1", - "is-ci": "^3.0.0", - "is-installed-globally": "~0.4.0", - "lazy-ass": "^1.6.0", - "listr2": "^3.8.3", - "lodash": "^4.17.21", - "log-symbols": "^4.0.0", - "minimist": "^1.2.6", - "ospath": "^1.2.2", - "pretty-bytes": "^5.6.0", - "proxy-from-env": "1.0.0", - "request-progress": "^3.0.0", - "semver": "^7.3.2", - "supports-color": "^8.1.1", - "tmp": "~0.2.1", - "untildify": "^4.0.0", - "yauzl": "^2.10.0" - }, - "bin": { - "cypress": "bin/cypress" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/cypress/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/cypress/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/cypress/node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cypress/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/cypress/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", "dev": true }, - "node_modules/cypress/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cypress/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/cypress/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/cytoscape": { - "version": "3.30.0", - "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.30.0.tgz", - "integrity": "sha512-l590mjTHT6/Cbxp13dGPC2Y7VXdgc+rUeF8AnF/JPzhjNevbDJfObnJgaSjlldOgBQZbue+X6IUZ7r5GAgvauQ==", + "version": "3.30.2", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.30.2.tgz", + "integrity": "sha512-oICxQsjW8uSaRmn4UK/jkczKOqTrVqt5/1WL0POiJUT2EKNc9STM4hYFHv917yu55aTBMFNRzymlJhVAiWPCxw==", + "optional": true, "engines": { "node": ">=0.10" } @@ -8606,6 +7688,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", + "optional": true, "dependencies": { "cose-base": "^1.0.0" }, @@ -8617,6 +7700,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz", "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==", + "optional": true, "dependencies": { "cose-base": "^2.2.0" }, @@ -8628,6 +7712,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz", "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==", + "optional": true, "dependencies": { "layout-base": "^2.0.0" } @@ -8635,12 +7720,14 @@ "node_modules/cytoscape-fcose/node_modules/layout-base": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz", - "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==" + "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==", + "optional": true }, "node_modules/d3": { "version": "7.9.0", "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "optional": true, "dependencies": { "d3-array": "3", "d3-axis": "3", @@ -8681,6 +7768,7 @@ "version": "3.2.4", "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "optional": true, "dependencies": { "internmap": "1 - 2" }, @@ -8692,6 +7780,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "optional": true, "engines": { "node": ">=12" } @@ -8700,6 +7789,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "optional": true, "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", @@ -8715,6 +7805,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "optional": true, "dependencies": { "d3-path": "1 - 3" }, @@ -8726,6 +7817,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "optional": true, "engines": { "node": ">=12" } @@ -8734,6 +7826,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "optional": true, "dependencies": { "d3-array": "^3.2.0" }, @@ -8745,6 +7838,7 @@ "version": "6.0.4", "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "optional": true, "dependencies": { "delaunator": "5" }, @@ -8756,6 +7850,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "optional": true, "engines": { "node": ">=12" } @@ -8764,6 +7859,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "optional": true, "dependencies": { "d3-dispatch": "1 - 3", "d3-selection": "3" @@ -8776,6 +7872,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "optional": true, "dependencies": { "commander": "7", "iconv-lite": "0.6", @@ -8800,14 +7897,28 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "optional": true, "engines": { "node": ">= 10" } }, + "node_modules/d3-dsv/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/d3-ease": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "optional": true, "engines": { "node": ">=12" } @@ -8816,6 +7927,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "optional": true, "dependencies": { "d3-dsv": "1 - 3" }, @@ -8827,6 +7939,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "optional": true, "dependencies": { "d3-dispatch": "1 - 3", "d3-quadtree": "1 - 3", @@ -8840,6 +7953,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "optional": true, "engines": { "node": ">=12" } @@ -8848,6 +7962,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "optional": true, "dependencies": { "d3-array": "2.5.0 - 3" }, @@ -8859,6 +7974,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "optional": true, "engines": { "node": ">=12" } @@ -8867,6 +7983,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "optional": true, "dependencies": { "d3-color": "1 - 3" }, @@ -8878,6 +7995,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "optional": true, "engines": { "node": ">=12" } @@ -8886,6 +8004,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "optional": true, "engines": { "node": ">=12" } @@ -8894,6 +8013,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "optional": true, "engines": { "node": ">=12" } @@ -8902,4365 +8022,902 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "optional": true, "engines": { "node": ">=12" } }, - "node_modules/d3-scale": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", - "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "optional": true, "dependencies": { - "d3-array": "2.10.0 - 3", - "d3-format": "1 - 3", - "d3-interpolate": "1.2.0 - 3", - "d3-time": "2.1.1 - 3", - "d3-time-format": "2 - 4" - }, - "engines": { - "node": ">=12" + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" } }, - "node_modules/d3-scale-chromatic": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", - "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "optional": true, "dependencies": { - "d3-color": "1 - 3", - "d3-interpolate": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-selection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", - "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", - "engines": { - "node": ">=12" + "internmap": "^1.0.0" } - }, - "node_modules/d3-shape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", - "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", - "dependencies": { - "d3-path": "^3.1.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-time": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", - "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", - "dependencies": { - "d3-array": "2 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-time-format": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", - "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", - "dependencies": { - "d3-time": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-timer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", - "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-transition": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", - "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", - "dependencies": { - "d3-color": "1 - 3", - "d3-dispatch": "1 - 3", - "d3-ease": "1 - 3", - "d3-interpolate": "1 - 3", - "d3-timer": "1 - 3" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "d3-selection": "2 - 3" - } - }, - "node_modules/d3-zoom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", - "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-drag": "2 - 3", - "d3-interpolate": "1 - 3", - "d3-selection": "2 - 3", - "d3-transition": "2 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/dagre-d3-es": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.9.tgz", - "integrity": "sha512-rYR4QfVmy+sR44IBDvVtcAmOReGBvRCWDpO2QjYwqgh9yijw6eSHBqaPG/LIOEy7aBsniLvtMW6pg19qJhq60w==", - "dependencies": { - "d3": "^7.8.2", - "lodash-es": "^4.17.21" - } - }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/data-urls": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", - "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", - "dev": true, - "dependencies": { - "abab": "^2.0.6", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^11.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/data-urls/node_modules/whatwg-url": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", - "dev": true, - "dependencies": { - "tr46": "^3.0.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/data-view-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", - "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", - "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", - "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/date-fns": { - "version": "2.30.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", - "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", - "dependencies": { - "@babel/runtime": "^7.21.0" - }, - "engines": { - "node": ">=0.11" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/date-fns" - } - }, - "node_modules/date-fns/node_modules/@babel/runtime": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz", - "integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/date-fns/node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" - }, - "node_modules/dayjs": { - "version": "1.11.11", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz", - "integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==" - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-2.0.0.tgz", - "integrity": "sha512-Ikpp5scV3MSYxY39ymh45ZLEecsTdv/Xj2CaQfI8RLMuwi7XvjX9H/fhraiSuU+C5w5NTDu4ZU72xNiZnurBPg==", - "dev": true, - "dependencies": { - "xregexp": "4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/decamelize-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", - "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", - "dev": true, - "dependencies": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decamelize-keys/node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decamelize-keys/node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decimal.js": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", - "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", - "dev": true - }, - "node_modules/decode-uri-component": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/default-gateway": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", - "dev": true, - "dependencies": { - "execa": "^5.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/default-gateway/node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/default-gateway/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-gateway/node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/defaults": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "dev": true, - "dependencies": { - "clone": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/delaunator": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", - "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", - "dependencies": { - "robust-predicates": "^3.0.2" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/delegate": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", - "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==" - }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "dev": true - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/dependency-graph": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", - "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true - }, - "node_modules/dicer": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", - "integrity": "sha512-FDvbtnq7dzlPz0wyYlOExifDEZcu8h+rErEXgfxqmLfRfC/kJidEFh4+effJRO3P0xmfqyPbSMG0LveNRfTKVg==", - "dev": true, - "dependencies": { - "readable-stream": "1.1.x", - "streamsearch": "0.1.2" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/dicer/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "node_modules/dicer/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/dicer/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diff-sequences": { - "version": "28.1.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", - "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dns-packet": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", - "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", - "dev": true, - "dependencies": { - "@leichtgewicht/ip-codec": "^2.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/doctypes": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", - "integrity": "sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==", - "dev": true - }, - "node_modules/dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "dev": true, - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domexception": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", - "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", - "deprecated": "Use your platform's native DOMException instead", - "dev": true, - "dependencies": { - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "dev": true, - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/dompurify": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.3.tgz", - "integrity": "sha512-q6QaLcakcRjebxjg8/+NP+h0rPfatOgOzc46Fst9VAA3jF2ApfKBNKMzdP4DYTqtUMXSCd5pRS/8Po/OmoCHZQ==" - }, - "node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dev": true, - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/dotenv-cli": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-7.4.2.tgz", - "integrity": "sha512-SbUj8l61zIbzyhIbg0FwPJq6+wjbzdn9oEtozQpZ6kW2ihCcapKVZj49oCT3oPM+mgQm+itgvUQcG5szxVrZTA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "dotenv": "^16.3.0", - "dotenv-expand": "^10.0.0", - "minimist": "^1.2.6" - }, - "bin": { - "dotenv": "cli.js" - } - }, - "node_modules/dotenv-expand": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", - "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/dropzone": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/dropzone/-/dropzone-5.9.3.tgz", - "integrity": "sha512-Azk8kD/2/nJIuVPK+zQ9sjKMRIpRvNyqn9XwbBHNq+iNuSccbJS6hwm1Woy0pMST0erSo0u4j+KJaodndDk4vA==", - "dev": true - }, - "node_modules/duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" - }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dev": true, - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/ecc-jsbn/node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true - }, - "node_modules/ejs": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", - "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", - "dev": true, - "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/elasticlunr": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/elasticlunr/-/elasticlunr-0.9.5.tgz", - "integrity": "sha512-5YM9LFQgVYfuLNEoqMqVWIBuF2UNCA+xu/jz1TyryLN/wmBcQSb+GNAwvLKvEpGESwgGN8XA1nbLAt6rKlyHYQ==", - "dev": true - }, - "node_modules/electron-to-chromium": { - "version": "1.4.827", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.827.tgz", - "integrity": "sha512-VY+J0e4SFcNfQy19MEoMdaIcZLmDCprqvBtkii1WTCTQHpRvf5N8+3kTYCgL/PcntvwQvmMJWTuDPsq+IlhWKQ==" - }, - "node_modules/elkjs": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.8.2.tgz", - "integrity": "sha512-L6uRgvZTH+4OF5NE/MBbzQx/WYpru1xCBE9respNj6qznEewGUIfhzmm7horWWxbNO2M0WckQypGctR8lH79xQ==" - }, - "node_modules/emittery": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", - "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/emoji-toolkit": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/emoji-toolkit/-/emoji-toolkit-6.6.0.tgz", - "integrity": "sha512-pEu0kow2p1N8zCKnn/L6H0F3rWUBB3P3hVjr/O5yl1fK7N9jU4vO4G7EFapC5Y3XwZLUCY0FZbOPyTkH+4V2eQ==" - }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enhanced-resolve": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", - "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/enquirer": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", - "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true - }, - "node_modules/errno": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", - "dev": true, - "optional": true, - "dependencies": { - "prr": "~1.0.1" - }, - "bin": { - "errno": "cli.js" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.23.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", - "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "arraybuffer.prototype.slice": "^1.0.3", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "data-view-buffer": "^1.0.1", - "data-view-byte-length": "^1.0.1", - "data-view-byte-offset": "^1.0.0", - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-set-tostringtag": "^2.0.3", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.4", - "get-symbol-description": "^1.0.2", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "hasown": "^2.0.2", - "internal-slot": "^1.0.7", - "is-array-buffer": "^3.0.4", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.1", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.3", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.13", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.5", - "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.2", - "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.9", - "string.prototype.trimend": "^1.0.8", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.2", - "typed-array-byte-length": "^1.0.1", - "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.6", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.15" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-module-lexer": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", - "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", - "dev": true - }, - "node_modules/es-object-atoms": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", - "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", - "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/esbuild": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.49.tgz", - "integrity": "sha512-/TlVHhOaq7Yz8N1OJrjqM3Auzo5wjvHFLk+T8pIue+fhnhIMpfAzsG6PLVMbFveVxqD2WOp3QHei+52IMUNmCw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "esbuild-android-64": "0.14.49", - "esbuild-android-arm64": "0.14.49", - "esbuild-darwin-64": "0.14.49", - "esbuild-darwin-arm64": "0.14.49", - "esbuild-freebsd-64": "0.14.49", - "esbuild-freebsd-arm64": "0.14.49", - "esbuild-linux-32": "0.14.49", - "esbuild-linux-64": "0.14.49", - "esbuild-linux-arm": "0.14.49", - "esbuild-linux-arm64": "0.14.49", - "esbuild-linux-mips64le": "0.14.49", - "esbuild-linux-ppc64le": "0.14.49", - "esbuild-linux-riscv64": "0.14.49", - "esbuild-linux-s390x": "0.14.49", - "esbuild-netbsd-64": "0.14.49", - "esbuild-openbsd-64": "0.14.49", - "esbuild-sunos-64": "0.14.49", - "esbuild-windows-32": "0.14.49", - "esbuild-windows-64": "0.14.49", - "esbuild-windows-arm64": "0.14.49" - } - }, - "node_modules/esbuild-android-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.49.tgz", - "integrity": "sha512-vYsdOTD+yi+kquhBiFWl3tyxnj2qZJsl4tAqwhT90ktUdnyTizgle7TjNx6Ar1bN7wcwWqZ9QInfdk2WVagSww==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-android-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.49.tgz", - "integrity": "sha512-g2HGr/hjOXCgSsvQZ1nK4nW/ei8JUx04Li74qub9qWrStlysaVmadRyTVuW32FGIpLQyc5sUjjZopj49eGGM2g==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.49.tgz", - "integrity": "sha512-3rvqnBCtX9ywso5fCHixt2GBCUsogNp9DjGmvbBohh31Ces34BVzFltMSxJpacNki96+WIcX5s/vum+ckXiLYg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.49.tgz", - "integrity": "sha512-XMaqDxO846srnGlUSJnwbijV29MTKUATmOLyQSfswbK/2X5Uv28M9tTLUJcKKxzoo9lnkYPsx2o8EJcTYwCs/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.49.tgz", - "integrity": "sha512-NJ5Q6AjV879mOHFri+5lZLTp5XsO2hQ+KSJYLbfY9DgCu8s6/Zl2prWXVANYTeCDLlrIlNNYw8y34xqyLDKOmQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.49.tgz", - "integrity": "sha512-lFLtgXnAc3eXYqj5koPlBZvEbBSOSUbWO3gyY/0+4lBdRqELyz4bAuamHvmvHW5swJYL7kngzIZw6kdu25KGOA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-32": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.49.tgz", - "integrity": "sha512-zTTH4gr2Kb8u4QcOpTDVn7Z8q7QEIvFl/+vHrI3cF6XOJS7iEI1FWslTo3uofB2+mn6sIJEQD9PrNZKoAAMDiA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.49.tgz", - "integrity": "sha512-hYmzRIDzFfLrB5c1SknkxzM8LdEUOusp6M2TnuQZJLRtxTgyPnZZVtyMeCLki0wKgYPXkFsAVhi8vzo2mBNeTg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.49.tgz", - "integrity": "sha512-iE3e+ZVv1Qz1Sy0gifIsarJMQ89Rpm9mtLSRtG3AH0FPgAzQ5Z5oU6vYzhc/3gSPi2UxdCOfRhw2onXuFw/0lg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.49.tgz", - "integrity": "sha512-KLQ+WpeuY+7bxukxLz5VgkAAVQxUv67Ft4DmHIPIW+2w3ObBPQhqNoeQUHxopoW/aiOn3m99NSmSV+bs4BSsdA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-mips64le": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.49.tgz", - "integrity": "sha512-n+rGODfm8RSum5pFIqFQVQpYBw+AztL8s6o9kfx7tjfK0yIGF6tm5HlG6aRjodiiKkH2xAiIM+U4xtQVZYU4rA==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-ppc64le": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.49.tgz", - "integrity": "sha512-WP9zR4HX6iCBmMFH+XHHng2LmdoIeUmBpL4aL2TR8ruzXyT4dWrJ5BSbT8iNo6THN8lod6GOmYDLq/dgZLalGw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-riscv64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.49.tgz", - "integrity": "sha512-h66ORBz+Dg+1KgLvzTVQEA1LX4XBd1SK0Fgbhhw4akpG/YkN8pS6OzYI/7SGENiN6ao5hETRDSkVcvU9NRtkMQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-s390x": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.49.tgz", - "integrity": "sha512-DhrUoFVWD+XmKO1y7e4kNCqQHPs6twz6VV6Uezl/XHYGzM60rBewBF5jlZjG0nCk5W/Xy6y1xWeopkrhFFM0sQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-netbsd-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.49.tgz", - "integrity": "sha512-BXaUwFOfCy2T+hABtiPUIpWjAeWK9P8O41gR4Pg73hpzoygVGnj0nI3YK4SJhe52ELgtdgWP/ckIkbn2XaTxjQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-openbsd-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.49.tgz", - "integrity": "sha512-lP06UQeLDGmVPw9Rg437Btu6J9/BmyhdoefnQ4gDEJTtJvKtQaUcOQrhjTq455ouZN4EHFH1h28WOJVANK41kA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-sunos-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.49.tgz", - "integrity": "sha512-4c8Zowp+V3zIWje329BeLbGh6XI9c/rqARNaj5yPHdC61pHI9UNdDxT3rePPJeWcEZVKjkiAS6AP6kiITp7FSw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-wasm": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.14.49.tgz", - "integrity": "sha512-5ddzZv8M3WI1fWZ5rEfK5cSA9swlWJcceKgqjKLLERC7FnlNW50kF7hxhpkyC0Z/4w7Xeyt3yUJ9QWNMDXLk2Q==", - "dev": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-32": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.49.tgz", - "integrity": "sha512-q7Rb+J9yHTeKr9QTPDYkqfkEj8/kcKz9lOabDuvEXpXuIcosWCJgo5Z7h/L4r7rbtTH4a8U2FGKb6s1eeOHmJA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.49.tgz", - "integrity": "sha512-+Cme7Ongv0UIUTniPqfTX6mJ8Deo7VXw9xN0yJEN1lQMHDppTNmKwAM3oGbD/Vqff+07K2gN0WfNkMohmG+dVw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.49.tgz", - "integrity": "sha512-v+HYNAXzuANrCbbLFJ5nmO3m5y2PGZWLe3uloAkLt87aXiO2mZr3BTmacZdjwNkNEHuH3bNtN8cak+mzVjVPfA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/escodegen": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", - "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", - "dev": true, - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/escodegen/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/escodegen/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", - "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", - "dev": true, - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", - "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlastindex": "^1.2.3", - "array.prototype.flat": "^1.3.2", - "array.prototype.flatmap": "^1.3.2", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.8.0", - "hasown": "^2.0.0", - "is-core-module": "^2.13.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.7", - "object.groupby": "^1.0.1", - "object.values": "^1.1.7", - "semver": "^6.3.1", - "tsconfig-paths": "^3.15.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/eslint-plugin-import/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-plugin-import/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-plugin-jsdoc": { - "version": "48.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.7.0.tgz", - "integrity": "sha512-5oiVf7Y+ZxGYQTlLq81X72n+S+hjvS/u0upAdbpPEeaIZILK3MKN8lm/6QqKioBjm/qZ0B5XpMQUtc2fUkqXAg==", - "dev": true, - "dependencies": { - "@es-joy/jsdoccomment": "~0.46.0", - "are-docs-informative": "^0.0.2", - "comment-parser": "1.4.1", - "debug": "^4.3.5", - "escape-string-regexp": "^4.0.0", - "esquery": "^1.6.0", - "parse-imports": "^2.1.1", - "semver": "^7.6.2", - "spdx-expression-parse": "^4.0.0", - "synckit": "^0.9.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" - } - }, - "node_modules/eslint-plugin-jsdoc/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-jsdoc/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-plugin-jsdoc/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-plugin-prefer-arrow": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prefer-arrow/-/eslint-plugin-prefer-arrow-1.2.3.tgz", - "integrity": "sha512-J9I5PKCOJretVuiZRGvPQxCbllxGAV/viI20JO3LYblAodofBxyMnZAJ+WGeClHgANnSJberTNoFWWjrWKBuXQ==", - "dev": true, - "peerDependencies": { - "eslint": ">=2.0.0" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/eslint/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/eslint/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/eslint/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/eslint/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventemitter-asyncresource": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz", - "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==", - "dev": true - }, - "node_modules/eventemitter2": { - "version": "6.4.9", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz", - "integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==", - "dev": true - }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/executable": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", - "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", - "dev": true, - "dependencies": { - "pify": "^2.2.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expect": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", - "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", - "dev": true, - "dependencies": { - "@jest/expect-utils": "^28.1.3", - "jest-get-type": "^28.0.2", - "jest-matcher-utils": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/exponential-backoff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", - "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", - "dev": true - }, - "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", - "dev": true, - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.2", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.6.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/express/node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/external-editor/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/external-editor/node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "dev": true, - "engines": [ - "node >=0.6.0" - ] - }, - "node_modules/fast-decode-uri-component": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", - "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastest-levenshtein": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", - "dev": true, - "engines": { - "node": ">= 4.9.1" - } - }, - "node_modules/fastify-plugin": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-4.5.1.tgz", - "integrity": "sha512-stRHYGeuqpEZTL1Ef0Ovr2ltazUT9g844X5z/zEBFLG8RYlpDiOCIG+ATvYEp+/zmc7sN29mcIMp8gvYplYPIQ==" - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "dev": true, - "dependencies": { - "websocket-driver": ">=0.5.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, - "dependencies": { - "pend": "~1.2.0" - } - }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/filelist": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", - "dev": true, - "dependencies": { - "minimatch": "^5.0.1" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "dev": true, - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/font-awesome": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz", - "integrity": "sha512-U6kGnykA/6bFmg1M/oT9EkFeIYv7JlX3bozwQJWiiLz6L0w3F5vBVPxHlwyX/vtNq1ckcpRKOB9f2Qal/VtFpg==", - "dev": true, - "engines": { - "node": ">=0.10.3" - } - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/foreground-child": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", - "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fraction.js": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", - "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", - "dev": true, - "engines": { - "node": "*" - }, - "funding": { - "type": "patreon", - "url": "https://github.com/sponsors/rawify" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true - }, - "node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs-monkey": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", - "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", - "dev": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "deprecated": "This package is no longer supported.", - "dev": true, - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", - "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/getos": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", - "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==", - "dev": true, - "dependencies": { - "async": "^3.2.0" - } - }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - } - }, - "node_modules/gettext-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/gettext-parser/-/gettext-parser-4.2.0.tgz", - "integrity": "sha512-aMgPyjC9W5Mz9tbFU8DcQ7GYMXoFWq633kaWGt4imlcpBWzDIWk7HY7nCSZTCJxyjRaLq9L/NEjMKkZ9gR630Q==", - "dev": true, - "dependencies": { - "content-type": "^1.0.4", - "encoding": "^0.1.13", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.1" - } - }, - "node_modules/glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "node_modules/global-dirs": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", - "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", - "dev": true, - "dependencies": { - "ini": "2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/global-dirs/node_modules/ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/global-modules": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", - "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", - "dev": true, - "dependencies": { - "global-prefix": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/global-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", - "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", - "dev": true, - "dependencies": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/global-prefix/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "node_modules/global-prefix/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globjoin": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", - "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==", - "dev": true - }, - "node_modules/good-listener": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", - "integrity": "sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==", - "dependencies": { - "delegate": "^3.1.2" - } - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/hads": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/hads/-/hads-3.0.3.tgz", - "integrity": "sha512-bbFWHXRz4OAru6pp/jNXCXHWife4vzAt+SY2KQMa4dvLDzl6fhFKS9TyYjAKlAfCDanTV2FCm9qmfGtTWJrHnQ==", - "dev": true, - "dependencies": { - "ace-builds": "^1.4.11", - "dropzone": "^5.7.0", - "elasticlunr": "^0.9.5", - "express": "^4.17.1", - "font-awesome": "^4.7.0", - "fs-extra": "^10.0.0", - "globby": "^11.0.0", - "highlight.js": "^11.2.0", - "humanize-string": "^2.1.0", - "lodash": "^4.17.15", - "marked": "^4.0.15", - "mermaid": "^9.0.1", - "moment": "^2.24.0", - "multer": "^1.4.2", - "normalize-path": "^3.0.0", - "octicons": "^4.4.0", - "open": "^8.2.1", - "pug": "^3.0.0", - "recursive-readdir": "^2.2.2", - "remove-markdown": "^0.5.0", - "shortid": "^2.2.15", - "yargs": "^17.1.1" - }, - "bin": { - "hads": "bin/hads" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/hads/node_modules/marked": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", - "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", - "dev": true, - "bin": { - "marked": "bin/marked.js" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true - }, - "node_modules/hard-rejection": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hdr-histogram-js": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", - "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", - "dev": true, - "dependencies": { - "@assemblyscript/loader": "^0.10.1", - "base64-js": "^1.2.0", - "pako": "^1.0.3" - } - }, - "node_modules/hdr-histogram-percentiles-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", - "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", - "dev": true - }, - "node_modules/highlight.js": { - "version": "11.10.0", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.10.0.tgz", - "integrity": "sha512-SYVnVFswQER+zu1laSya563s+F8VDGt7o35d4utbamowvUNLLMovFqwCLSocpZTz3MgaSRA1IbqRWZv97dtErQ==", - "dev": true, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/hosted-git-info": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", - "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", - "dev": true, - "dependencies": { - "lru-cache": "^7.5.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "node_modules/hpack.js/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "node_modules/hpack.js/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/hpack.js/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/hpack.js/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/html-encoding-sniffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", - "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", - "dev": true, - "dependencies": { - "whatwg-encoding": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/html-entities": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", - "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/mdevils" - }, - { - "type": "patreon", - "url": "https://patreon.com/mdevils" - } - ] - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/html-tags": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", - "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "dev": true - }, - "node_modules/http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-parser-js": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", - "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", - "dev": true - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, + }, + "node_modules/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "optional": true + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "optional": true, "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" + "d3-path": "1" } }, - "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "optional": true + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "optional": true, "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" }, "engines": { - "node": ">= 6" + "node": ">=12" } }, - "node_modules/http-proxy-middleware": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", - "dev": true, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "optional": true, "dependencies": { - "@types/http-proxy": "^1.17.8", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" }, "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@types/express": "^4.17.13" - }, - "peerDependenciesMeta": { - "@types/express": { - "optional": true - } + "node": ">=12" } }, - "node_modules/http-proxy-middleware/node_modules/is-plain-obj": { + "node_modules/d3-selection": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", - "dev": true, + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "optional": true, "engines": { - "node": ">=10" + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "optional": true, + "dependencies": { + "d3-path": "^3.1.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=12" } }, - "node_modules/http-signature": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", - "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", - "dev": true, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "optional": true, "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^2.0.2", - "sshpk": "^1.14.1" + "d3-array": "2 - 3" }, "engines": { - "node": ">=0.10" + "node": ">=12" } }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "optional": true, "dependencies": { - "agent-base": "6", - "debug": "4" + "d3-time": "1 - 3" }, "engines": { - "node": ">= 6" + "node": ">=12" } }, - "node_modules/human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "dev": true, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "optional": true, "engines": { - "node": ">=8.12.0" + "node": ">=12" } }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "dev": true, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "optional": true, "dependencies": { - "ms": "^2.0.0" + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" } }, - "node_modules/humanize-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/humanize-string/-/humanize-string-2.1.0.tgz", - "integrity": "sha512-sQ+hqmxyXW8Cj7iqxcQxD7oSy3+AXnIZXdUF9lQMkzaG8dtbKAB8U7lCtViMnwQ+MpdCKsO2Kiij3G6UUXq/Xg==", - "dev": true, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "optional": true, "dependencies": { - "decamelize": "^2.0.0" + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" }, "engines": { - "node": ">=6" + "node": ">=12" } }, - "node_modules/husky": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", - "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", + "node_modules/dagre-d3-es": { + "version": "7.0.10", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.10.tgz", + "integrity": "sha512-qTCQmEhcynucuaZgY5/+ti3X/rnszKZhEQH/ZdWdtP1tA/y3VoHJzcVrO9pjjJCNpigfscAtoUB5ONcd2wNn0A==", + "optional": true, + "dependencies": { + "d3": "^7.8.2", + "lodash-es": "^4.17.21" + } + }, + "node_modules/date-format": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", + "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", "dev": true, - "bin": { - "husky": "lib/bin.js" - }, "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/typicode" + "node": ">=4.0" } }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "optional": true + }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "devOptional": true, "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" + "ms": "^2.1.3" }, "engines": { - "node": ">=0.10.0" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/default-browser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", "dev": true, + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, "engines": { - "node": "^10 || ^12 || >= 14" + "node": ">=18" }, - "peerDependencies": { - "postcss": "^8.1.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "node_modules/default-browser-id": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", "dev": true, "engines": { - "node": ">= 4" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ignore-walk": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-5.0.1.tgz", - "integrity": "sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw==", + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", "dev": true, "dependencies": { - "minimatch": "^5.0.1" + "execa": "^5.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">= 10" } }, - "node_modules/image-size": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", - "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", - "dev": true, - "optional": true, - "bin": { - "image-size": "bin/image-size.js" + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dependencies": { + "clone": "^1.0.2" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } - }, - "node_modules/immutable": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.6.tgz", - "integrity": "sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==", - "dev": true - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" }, "engines": { - "node": ">=6" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", "dev": true, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/import-lazy": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", - "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "node_modules/delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "optional": true, + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, + "node_modules/delegate": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", + "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==", + "optional": true + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true, "engines": { - "node": ">=8" + "node": ">= 0.8" } }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6" } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "dev": true, "engines": { - "node": ">=0.8.19" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", "dev": true, "engines": { "node": ">=8" } }, - "node_modules/infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "dev": true }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "node_modules/di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", + "dev": true }, - "node_modules/ini": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.0.tgz", - "integrity": "sha512-TxYQaeNW/N8ymDvwAxPyRbhMBtnEwuvaTYpOQkFx1nSeusgezHniEc/l35Vo4iCq/mMiTJbpD7oYxN98hFlfmw==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true }, - "node_modules/inquirer": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", - "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.21", - "mute-stream": "0.0.8", - "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.5.5", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6", - "wrap-ansi": "^7.0.0" + "path-type": "^4.0.0" }, "engines": { - "node": ">=12.0.0" + "node": ">=8" } }, - "node_modules/inquirer/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "@leichtgewicht/ip-codec": "^2.0.1" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=6" } }, - "node_modules/inquirer/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" } }, - "node_modules/inquirer/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" }, - "engines": { - "node": ">=7.0.0" + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, - "node_modules/inquirer/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/inquirer/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "dev": true, - "engines": { - "node": ">=8" - } + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] }, - "node_modules/inquirer/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "domelementtype": "^2.3.0" }, "engines": { - "node": ">=8" + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" } }, - "node_modules/internal-slot": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "node_modules/dompurify": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.6.tgz", + "integrity": "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==", + "optional": true + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "dev": true, "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" }, - "engines": { - "node": ">= 0.4" + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "node_modules/internmap": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", - "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.4.699", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.699.tgz", + "integrity": "sha512-I7q3BbQi6e4tJJN5CRcyvxhK0iJb34TV8eJQcgh+fR2fQ8miMgZcEInckCo1U9exDHbfz7DLDnFn8oqH/VcRKw==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/emoji-toolkit": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/emoji-toolkit/-/emoji-toolkit-9.0.1.tgz", + "integrity": "sha512-sMMNqKNLVHXJfIKoPbrRJwtYuysVNC9GlKetr72zE3SSVbHqoeDLWVrxP0uM0AE0qvdl3hbUk+tJhhwXZrDHaw==", + "optional": true + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, "engines": { - "node": ">=12" + "node": ">= 4" } }, - "node_modules/ip-address": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", - "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "dev": true, - "dependencies": { - "jsbn": "1.1.0", - "sprintf-js": "^1.1.3" - }, "engines": { - "node": ">= 12" + "node": ">= 0.8" } }, - "node_modules/ip-address/node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "dev": true - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", "dev": true, - "engines": { - "node": ">= 0.10" + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" } }, - "node_modules/is-array-buffer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, + "optional": true, "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "node_modules/engine.io": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", + "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", "dev": true, "dependencies": { - "has-bigints": "^1.0.1" + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=10.2.0" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dependencies": { - "binary-extensions": "^2.0.0" - }, + "node_modules/engine.io-parser": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", + "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==", + "dev": true, "engines": { - "node": ">=8" + "node": ">=10.0.0" } }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "node_modules/enhanced-resolve": { + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.1.tgz", + "integrity": "sha512-4U5pNsuDl0EhuZpq46M5xPslstkviJuhrdobaRDBk2Jy2KO37FDAJl4lb2KlNabxT0m4MTK2UHNrsAcphE8nyw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" }, "engines": { - "node": ">= 0.4" + "node": ">=10.13.0" + } + }, + "node_modules/ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", + "dev": true + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "devOptional": true, + "engines": { + "node": ">=0.12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", "dev": true, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=6" } }, - "node_modules/is-ci": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", - "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "dev": true, + "optional": true, "dependencies": { - "ci-info": "^3.2.0" + "prr": "~1.0.1" }, "bin": { - "is-ci": "bin.js" + "errno": "cli.js" } }, - "node_modules/is-core-module": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", - "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", - "dev": true, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "is-arrayish": "^0.2.1" } }, - "node_modules/is-data-view": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", - "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", "dev": true, "dependencies": { - "is-typed-array": "^1.1.13" + "get-intrinsic": "^1.2.4" }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "node_modules/es-module-lexer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", + "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.3.tgz", + "integrity": "sha512-Kgq0/ZsAPzKrbOjCQcjoSmPoWhlcVnGAUo7jvaLHoxW1Drto0KGkR1xBNg2Cp43b9ImvxmPEJZ9xkfcnqPsfBw==", "dev": true, + "hasInstallScript": true, "bin": { - "is-docker": "cli.js" + "esbuild": "bin/esbuild" }, "engines": { - "node": ">=8" + "node": ">=12" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-expression": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz", - "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==", - "dev": true, - "dependencies": { - "acorn": "^7.1.1", - "object-assign": "^4.1.1" + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.3", + "@esbuild/android-arm": "0.21.3", + "@esbuild/android-arm64": "0.21.3", + "@esbuild/android-x64": "0.21.3", + "@esbuild/darwin-arm64": "0.21.3", + "@esbuild/darwin-x64": "0.21.3", + "@esbuild/freebsd-arm64": "0.21.3", + "@esbuild/freebsd-x64": "0.21.3", + "@esbuild/linux-arm": "0.21.3", + "@esbuild/linux-arm64": "0.21.3", + "@esbuild/linux-ia32": "0.21.3", + "@esbuild/linux-loong64": "0.21.3", + "@esbuild/linux-mips64el": "0.21.3", + "@esbuild/linux-ppc64": "0.21.3", + "@esbuild/linux-riscv64": "0.21.3", + "@esbuild/linux-s390x": "0.21.3", + "@esbuild/linux-x64": "0.21.3", + "@esbuild/netbsd-x64": "0.21.3", + "@esbuild/openbsd-x64": "0.21.3", + "@esbuild/sunos-x64": "0.21.3", + "@esbuild/win32-arm64": "0.21.3", + "@esbuild/win32-ia32": "0.21.3", + "@esbuild/win32-x64": "0.21.3" } }, - "node_modules/is-expression/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "node_modules/esbuild-wasm": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.21.3.tgz", + "integrity": "sha512-DMOV+eeVra0yVq3XIojfczdEQsz+RiFnpEj7lqs8Gux9mlTpN7yIbw0a4KzLspn0Uhw6UVEH3nUAidSqc/rcQg==", "dev": true, "bin": { - "acorn": "bin/acorn" + "esbuild": "bin/esbuild" }, "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "engines": { "node": ">=6" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dependencies": { - "is-extglob": "^2.1.1" - }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "engines": { - "node": ">=0.10.0" + "node": ">=0.8.0" } }, - "node_modules/is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "node_modules/eslint": { + "version": "9.12.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.12.0.tgz", + "integrity": "sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw==", "dev": true, "dependencies": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.18.0", + "@eslint/core": "^0.6.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.12.0", + "@eslint/plugin-kit": "^0.2.0", + "@humanfs/node": "^0.16.5", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.1.0", + "eslint-visitor-keys": "^4.1.0", + "espree": "^10.2.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "text-table": "^0.2.0" }, - "engines": { - "node": ">=10" + "bin": { + "eslint": "bin/eslint.js" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "dev": true - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "dev": true, "engines": { - "node": ">= 0.4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" + "url": "https://eslint.org/donate" }, - "engines": { - "node": ">= 0.4" + "peerDependencies": { + "jiti": "*" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, - "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8.0.0" } }, - "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "node_modules/is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "node_modules/eslint/node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", "dev": true }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", - "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "call-bind": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" + "color-convert": "^2.0.1" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, "engines": { "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "has-symbols": "^1.0.2" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/is-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "which-typed-array": "^1.1.14" + "color-name": "~1.1.4" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=7.0.0" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "engines": { "node": ">=10" @@ -13269,126 +8926,120 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "node_modules/eslint/node_modules/eslint-scope": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.1.0.tgz", + "integrity": "sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://opencollective.com/eslint" } }, - "node_modules/is-what": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", - "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", - "dev": true - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", + "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", "dev": true, - "dependencies": { - "is-docker": "^2.0.0" - }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=4.0" } }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" + "is-glob": "^4.0.3" }, "engines": { - "node": ">=8" + "node": ">=10.13.0" } }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "bin": { - "semver": "bin/semver.js" + "engines": { + "node": ">=8" } }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" + "p-locate": "^5.0.0" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/istanbul-lib-report/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=8" + "node": "*" } }, - "node_modules/istanbul-lib-report/node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "dependencies": { - "semver": "^7.5.3" + "yocto-queue": "^0.1.0" }, "engines": { "node": ">=10" @@ -13397,19 +9048,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/istanbul-lib-report/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, - "bin": { - "semver": "bin/semver.js" + "dependencies": { + "p-limit": "^3.0.2" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { + "node_modules/eslint/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", @@ -13421,206 +9075,145 @@ "node": ">=8" } }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "node_modules/eslint/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/istanbul-lib-source-maps/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", - "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "node_modules/espree": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz", + "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==", "dev": true, "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.1.0" }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dependencies": { - "@isaacs/cliui": "^8.0.2" + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", + "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" + "url": "https://opencollective.com/eslint" } }, - "node_modules/jake": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.1.tgz", - "integrity": "sha512-61btcOHNnLnsOdtLgA5efqQWjnSi/vow5HbI7HMdKKWqvrKR1bLK3BPlJn9gcSaP2ewuamUSMB5XEy76KUIS2w==", + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, - "dependencies": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.4", - "minimatch": "^3.1.2" - }, "bin": { - "jake": "bin/cli.js" + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" }, "engines": { - "node": ">=10" + "node": ">=4" } }, - "node_modules/jake/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "estraverse": "^5.1.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jake/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "node": ">=0.10" } }, - "node_modules/jake/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=4.0" } }, - "node_modules/jake/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "estraverse": "^5.2.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=4.0" } }, - "node_modules/jake/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jake/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "engines": { - "node": ">=8" + "node": ">=4.0" } }, - "node_modules/jake/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, "engines": { - "node": "*" + "node": ">=4.0" } }, - "node_modules/jake/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/jest": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.3.tgz", - "integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==", + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, - "dependencies": { - "@jest/core": "^28.1.3", - "@jest/types": "^28.1.3", - "import-local": "^3.0.2", - "jest-cli": "^28.1.3" - }, - "bin": { - "jest": "bin/jest.js" - }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "node": ">= 0.6" } }, - "node_modules/jest-changed-files": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.1.3.tgz", - "integrity": "sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA==", + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true, - "dependencies": { - "execa": "^5.0.0", - "p-limit": "^3.1.0" - }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": ">=0.8.x" } }, - "node_modules/jest-changed-files/node_modules/execa": { + "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", @@ -13643,1580 +9236,1401 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/jest-changed-files/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "node_modules/execa/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "dev": true + }, + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dev": true, - "engines": { - "node": ">=10" + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">= 0.10.0" } }, - "node_modules/jest-changed-files/node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "node_modules/express/node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "dev": true, "engines": { - "node": ">=10.17.0" + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" } }, - "node_modules/jest-circus": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-28.1.3.tgz", - "integrity": "sha512-cZ+eS5zc79MBwt+IhQhiEp0OeBddpc1n8MBo1nMB8A7oPMKEO+Sre+wHaLJexQUj9Ya/8NOBY0RESUgYjB6fow==", + "node_modules/express/node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "dev": true, "dependencies": { - "@jest/environment": "^28.1.3", - "@jest/expect": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^28.1.3", - "jest-matcher-utils": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-runtime": "^28.1.3", - "jest-snapshot": "^28.1.3", - "jest-util": "^28.1.3", - "p-limit": "^3.1.0", - "pretty-format": "^28.1.3", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": ">= 0.8" } }, - "node_modules/jest-circus/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/express/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">= 0.8" } }, - "node_modules/jest-circus/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=4" } }, - "node_modules/jest-circus/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" }, "engines": { - "node": ">=7.0.0" + "node": ">=8.6.0" } }, - "node_modules/jest-circus/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, - "node_modules/jest-circus/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, - "engines": { - "node": ">=8" + "dependencies": { + "reusify": "^1.0.4" } }, - "node_modules/jest-circus/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "websocket-driver": ">=0.5.1" }, "engines": { - "node": ">=8" + "node": ">=0.8.0" } }, - "node_modules/jest-cli": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-28.1.3.tgz", - "integrity": "sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ==", + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "dependencies": { - "@jest/core": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/types": "^28.1.3", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^28.1.3", - "jest-util": "^28.1.3", - "jest-validate": "^28.1.3", - "prompts": "^2.0.1", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "node": ">=16.0.0" } }, - "node_modules/jest-cli/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "to-regex-range": "^5.0.1" }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-cli/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">= 0.8" } }, - "node_modules/jest-cli/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "ms": "2.0.0" } }, - "node_modules/jest-cli/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "node_modules/jest-cli/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-cli/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/finalhandler/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "ee-first": "1.1.1" }, "engines": { - "node": ">=8" + "node": ">= 0.8" } }, - "node_modules/jest-config": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.1.3.tgz", - "integrity": "sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ==", + "node_modules/find-cache-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", "dev": true, "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^28.1.3", - "@jest/types": "^28.1.3", - "babel-jest": "^28.1.3", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^28.1.3", - "jest-environment-node": "^28.1.3", - "jest-get-type": "^28.0.2", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.1.3", - "jest-runner": "^28.1.3", - "jest-util": "^28.1.3", - "jest-validate": "^28.1.3", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^28.1.3", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" + "node": ">=14.16" }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-config/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-config/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "node_modules/flat": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/flat/-/flat-6.0.1.tgz", + "integrity": "sha512-/3FfIa8mbrg3xE7+wAhWeV+bd7L2Mof+xtZb5dRDKZ+wDvYJK4WDYeIOuOhre5Yv5aQObZrlbRmk3RTSiuQBtw==", + "bin": { + "flat": "cli.js" + }, + "engines": { + "node": ">=18" } }, - "node_modules/jest-config/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=16" } }, - "node_modules/jest-config/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], "engines": { - "node": ">=7.0.0" + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } } }, - "node_modules/jest-config/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-config/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" }, "engines": { - "node": "*" + "node": ">=14" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/jest-config/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true, "engines": { - "node": ">=8" + "node": ">= 0.6" } }, - "node_modules/jest-config/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, "engines": { "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" } }, - "node_modules/jest-config/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { - "node": ">=8" + "node": ">= 0.6" } }, - "node_modules/jest-diff": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", - "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", - "dev": true, + "node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^28.1.1", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.3" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": ">=14.14" } }, - "node_modules/jest-diff/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "minipass": "^7.0.3" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/jest-diff/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/jest-diff/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-diff/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-diff/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, "engines": { - "node": ">=8" + "node": ">=6.9.0" } }, - "node_modules/jest-diff/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "engines": { - "node": ">=8" + "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/jest-docblock": { - "version": "28.1.1", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.1.1.tgz", - "integrity": "sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA==", + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, "dependencies": { - "detect-newline": "^3.0.0" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-each": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-28.1.3.tgz", - "integrity": "sha512-arT1z4sg2yABU5uogObVPvSlSMQlDA48owx07BDPAiasW0yYpYHYOo4HHLz9q0BVzDVU4hILFjzJw0So9aCL/g==", + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, - "dependencies": { - "@jest/types": "^28.1.3", - "chalk": "^4.0.0", - "jest-get-type": "^28.0.2", - "jest-util": "^28.1.3", - "pretty-format": "^28.1.3" - }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": ">=8.0.0" } }, - "node_modules/jest-each/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-each/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/jest-each/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "is-glob": "^4.0.1" }, "engines": { - "node": ">=7.0.0" + "node": ">= 6" } }, - "node_modules/jest-each/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "dev": true }, - "node_modules/jest-each/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/jest-each/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-environment-jsdom": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-28.1.3.tgz", - "integrity": "sha512-HnlGUmZRdxfCByd3GM2F100DgQOajUBzEitjGqIREcb45kGjZvRrKUdlaF6escXBdcXNl0OBh+1ZrfeZT3GnAg==", - "dev": true, + "node_modules/good-listener": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", + "integrity": "sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==", + "optional": true, "dependencies": { - "@jest/environment": "^28.1.3", - "@jest/fake-timers": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/jsdom": "^16.2.4", - "@types/node": "*", - "jest-mock": "^28.1.3", - "jest-util": "^28.1.3", - "jsdom": "^19.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "delegate": "^3.1.2" } }, - "node_modules/jest-environment-node": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.1.3.tgz", - "integrity": "sha512-ugP6XOhEpjAEhGYvp5Xj989ns5cB1K6ZdjBYuS30umT4CQEETaxSiPcZ/E1kFktX4GkrcM4qu07IIlDYX1gp+A==", + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "dev": true, "dependencies": { - "@jest/environment": "^28.1.3", - "@jest/fake-timers": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/node": "*", - "jest-mock": "^28.1.3", - "jest-util": "^28.1.3" + "get-intrinsic": "^1.1.3" }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, - "node_modules/jest-haste-map": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", - "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", - "dev": true, - "dependencies": { - "@jest/types": "^28.1.3", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^28.0.2", - "jest-util": "^28.1.3", - "jest-worker": "^28.1.3", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true }, - "node_modules/jest-leak-detector": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz", - "integrity": "sha512-WFVJhnQsiKtDEo5lG2mM0v40QWnBM+zMdHHyJs8AWZ7J0QZJS59MsyKeJHWhpBZBH32S48FOVvGyOFT1h0DlqA==", - "dev": true, - "dependencies": { - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.3" - }, + "node_modules/hachure-fill": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz", + "integrity": "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==", + "optional": true + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": ">=4" } }, - "node_modules/jest-matcher-utils": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", - "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^28.1.3", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.3" + "es-define-property": "^1.0.0" }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-matcher-utils/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-matcher-utils/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-matcher-utils/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "function-bind": "^1.1.2" }, "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-matcher-utils/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-matcher-utils/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/jest-matcher-utils/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, + "node_modules/highlight.js": { + "version": "11.9.0", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.9.0.tgz", + "integrity": "sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==", "engines": { - "node": ">=8" + "node": ">=12.0.0" } }, - "node_modules/jest-message-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", - "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^28.1.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^28.1.3", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "lru-cache": "^10.0.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/jest-message-util/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": "14 || >=16.14" } }, - "node_modules/jest-message-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" } }, - "node_modules/jest-message-util/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/jest-message-util/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, - "node_modules/jest-message-util/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-message-util/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "safe-buffer": "~5.1.0" } }, - "node_modules/jest-mock": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.3.tgz", - "integrity": "sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA==", + "node_modules/html-entities": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", "dev": true, - "dependencies": { - "@jest/types": "^28.1.3", - "@types/node": "*" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", "dev": true, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" } }, - "node_modules/jest-preset-angular": { - "version": "12.2.2", - "resolved": "https://registry.npmjs.org/jest-preset-angular/-/jest-preset-angular-12.2.2.tgz", - "integrity": "sha512-aj5ZwVW6cGGzZKUn6e/jDwFgQh6FHy1zCCXWOeqFCuM3WODrbdUJ93zKrex18e9K1+PvOcP0e20yKbj3gwhfFg==", + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dev": true, "dependencies": { - "bs-logger": "^0.2.6", - "esbuild-wasm": ">=0.13.8", - "jest-environment-jsdom": "^28.0.0", - "pretty-format": "^28.0.0", - "ts-jest": "^28.0.0" + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" }, "engines": { - "node": "^14.15.0 || >=16.10.0" - }, - "optionalDependencies": { - "esbuild": ">=0.13.8" - }, - "peerDependencies": { - "@angular-devkit/build-angular": ">=0.1102.19 <15.0.0", - "@angular/compiler-cli": ">=11.2.14 <15.0.0", - "@angular/core": ">=11.2.14 <15.0.0", - "@angular/platform-browser-dynamic": ">=11.2.14 <15.0.0", - "jest": "^28.0.0", - "typescript": ">=4.3" + "node": ">= 0.8" } }, - "node_modules/jest-regex-util": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", - "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": ">= 0.8" } }, - "node_modules/jest-resolve": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.1.3.tgz", - "integrity": "sha512-Z1W3tTjE6QaNI90qo/BJpfnvpxtaFTFw5CDgwpyE/Kz8U/06N1Hjf4ia9quUhCh39qIGWF1ZuxFiBiJQwSEYKQ==", + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "dev": true, "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.3", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^28.1.3", - "jest-validate": "^28.1.3", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": ">=8.0.0" } }, - "node_modules/jest-resolve-dependencies": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.3.tgz", - "integrity": "sha512-qa0QO2Q0XzQoNPouMbCc7Bvtsem8eQgVPNkwn9LnS+R2n8DaVDPL/U1gngC0LTl1RYXJU0uJa2BMC2DbTfFrHA==", + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "dev": true, "dependencies": { - "jest-regex-util": "^28.0.2", - "jest-snapshot": "^28.1.3" + "agent-base": "^7.1.0", + "debug": "^4.3.4" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": ">= 14" } }, - "node_modules/jest-resolve/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/http-proxy-middleware": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.0.tgz", + "integrity": "sha512-36AV1fIaI2cWRzHo+rbcxhe3M3jUDCNzc4D5zRl57sEWRAxdXYtw7FSQKYY6PDKssiAKjLYypbssHk+xs/kMXw==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "@types/http-proxy": "^1.17.10", + "debug": "^4.3.4", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.5" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-resolve/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "agent-base": "^7.0.2", + "debug": "4" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">= 14" } }, - "node_modules/jest-resolve/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, "engines": { - "node": ">=7.0.0" + "node": ">=10.17.0" } }, - "node_modules/jest-resolve/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-resolve/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/hyperdyperid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", + "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", "dev": true, "engines": { - "node": ">=8" + "node": ">=10.18" } }, - "node_modules/jest-resolve/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "safer-buffer": ">= 2.1.2 < 3" }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/jest-runner": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.1.3.tgz", - "integrity": "sha512-GkMw4D/0USd62OVO0oEgjn23TM+YJa2U2Wu5zz9xsQB1MxWKDOlrnykPxnMsN0tnJllfLPinHTka61u0QhaxBA==", - "dev": true, - "dependencies": { - "@jest/console": "^28.1.3", - "@jest/environment": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.10.2", - "graceful-fs": "^4.2.9", - "jest-docblock": "^28.1.1", - "jest-environment-node": "^28.1.3", - "jest-haste-map": "^28.1.3", - "jest-leak-detector": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-resolve": "^28.1.3", - "jest-runtime": "^28.1.3", - "jest-util": "^28.1.3", - "jest-watcher": "^28.1.3", - "jest-worker": "^28.1.3", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-runner/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": "^10 || ^12 || >= 14" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/jest-runner/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">= 4" } }, - "node_modules/jest-runner/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/ignore-walk": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.5.tgz", + "integrity": "sha512-VuuG0wCnjhnylG1ABXT3dAuIpTNDs/G8jlpmwXY03fXoXy/8ZK8/T+hMzt8L4WnrLCJgdybqgPagnF/f97cg3A==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "minimatch": "^9.0.0" }, "engines": { - "node": ">=7.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/jest-runner/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-runner/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", "dev": true, + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/jest-runner/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, + "node_modules/immutable": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.6.tgz", + "integrity": "sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-runner/node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" } }, - "node_modules/jest-runner/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { - "node": ">=8" + "node": ">=0.8.19" } }, - "node_modules/jest-runtime": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.3.tgz", - "integrity": "sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw==", - "dev": true, - "dependencies": { - "@jest/environment": "^28.1.3", - "@jest/fake-timers": "^28.1.3", - "@jest/globals": "^28.1.3", - "@jest/source-map": "^28.1.2", - "@jest/test-result": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "execa": "^5.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-mock": "^28.1.3", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.1.3", - "jest-snapshot": "^28.1.3", - "jest-util": "^28.1.3", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-runtime/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-runtime/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "once": "^1.3.0", + "wrappy": "1" } }, - "node_modules/jest-runtime/node_modules/chalk": { + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", + "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", + "dev": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/jest-runtime/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/inquirer": { + "version": "9.2.22", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.22.tgz", + "integrity": "sha512-SqLLa/Oe5rZUagTR9z+Zd6izyatHglbmbvVofo1KzuVB54YHleWzeHNLoR7FOICGOeQSqeLh1cordb3MzhGcEw==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "@inquirer/figures": "^1.0.2", + "@ljharb/through": "^2.3.13", + "ansi-escapes": "^4.3.2", + "chalk": "^5.3.0", + "cli-cursor": "^3.1.0", + "cli-width": "^4.1.0", + "external-editor": "^3.1.0", + "lodash": "^4.17.21", + "mute-stream": "1.0.0", + "ora": "^5.4.1", + "run-async": "^3.0.0", + "rxjs": "^7.8.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=18" } }, - "node_modules/jest-runtime/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-runtime/node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "node_modules/inquirer/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, "engines": { - "node": ">=10" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-runtime/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "optional": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12" } }, - "node_modules/jest-runtime/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", "dev": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" }, "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">= 12" } }, - "node_modules/jest-runtime/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/ip-address/node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", "dev": true, "engines": { - "node": ">=8" + "node": ">= 10" } }, - "node_modules/jest-runtime/node_modules/human-signals": { + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-binary-path": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, "engines": { - "node": ">=10.17.0" + "node": ">=8" } }, - "node_modules/jest-runtime/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "hasown": "^2.0.0" }, - "engines": { - "node": "*" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-runtime/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "dev": true, - "dependencies": { - "has-flag": "^4.0.0" + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "engines": { "node": ">=8" } }, - "node_modules/jest-snapshot": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.3.tgz", - "integrity": "sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg==", + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^28.1.3", - "graceful-fs": "^4.2.9", - "jest-diff": "^28.1.3", - "jest-get-type": "^28.0.2", - "jest-haste-map": "^28.1.3", - "jest-matcher-utils": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3", - "natural-compare": "^1.4.0", - "pretty-format": "^28.1.3", - "semver": "^7.3.5" + "is-extglob": "^2.1.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": ">=0.10.0" } }, - "node_modules/jest-snapshot/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" }, "engines": { - "node": ">=8" + "node": ">=14.16" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-snapshot/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/is-inside-container/node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "bin": { + "is-docker": "cli.js" }, "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-snapshot/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", "engines": { - "node": ">=7.0.0" + "node": ">=8" } }, - "node_modules/jest-snapshot/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", "dev": true }, - "node_modules/jest-snapshot/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/is-network-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", + "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", "dev": true, "engines": { - "node": ">=8" + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-snapshot/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { - "node": ">=8" + "node": ">=0.12.0" } }, - "node_modules/jest-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", - "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", "dev": true, - "dependencies": { - "@jest/types": "^28.1.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-util/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "isobject": "^3.0.1" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=0.10.0" } }, - "node_modules/jest-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-util/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "is-docker": "^2.0.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=8" } }, - "node_modules/jest-util/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true }, - "node_modules/jest-util/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", "dev": true, "engines": { - "node": ">=8" + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" } }, - "node_modules/jest-util/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/jest-validate": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.1.3.tgz", - "integrity": "sha512-SZbOGBWEsaTxBGCOpsRWlXlvNkvTkY0XxRfh7zYmvd8uL5Qzyg0CHAXiXKROflh801quA6+/DsT4ODDthOC/OA==", + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, - "dependencies": { - "@jest/types": "^28.1.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^28.0.2", - "leven": "^3.1.0", - "pretty-format": "^28.1.3" - }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": ">=8" } }, - "node_modules/jest-validate/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/jest-validate/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", "supports-color": "^7.1.0" }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-validate/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" } }, - "node_modules/jest-validate/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-validate/node_modules/has-flag": { + "node_modules/istanbul-lib-report/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", @@ -15225,7 +10639,7 @@ "node": ">=8" } }, - "node_modules/jest-validate/node_modules/supports-color": { + "node_modules/istanbul-lib-report/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", @@ -15237,99 +10651,69 @@ "node": ">=8" } }, - "node_modules/jest-watcher": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.3.tgz", - "integrity": "sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==", + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, "dependencies": { - "@jest/test-result": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.10.2", - "jest-util": "^28.1.3", - "string-length": "^4.0.1" + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": ">=10" } }, - "node_modules/jest-watcher/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=0.10.0" } }, - "node_modules/jest-watcher/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=8" } }, - "node_modules/jest-watcher/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", "dependencies": { - "color-name": "~1.1.4" + "@isaacs/cliui": "^8.0.2" }, "engines": { - "node": ">=7.0.0" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/jest-watcher/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/jasmine-core": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.1.2.tgz", + "integrity": "sha512-2oIUMGn00FdUiqz6epiiJr7xcFyNYj3rDcfmnzfkBnHyBQ3cBQUs4mmyGsOb7TTLb9kxk7dBcmEmqhDKkBoDyA==", "dev": true }, - "node_modules/jest-watcher/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watcher/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-worker": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", - "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, "dependencies": { "@types/node": "*", @@ -15337,7 +10721,7 @@ "supports-color": "^8.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": ">= 10.13.0" } }, "node_modules/jest-worker/node_modules/has-flag": { @@ -15364,115 +10748,44 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/js-stringify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", - "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==", - "dev": true - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsbn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "dev": true - }, - "node_modules/jsdoc-type-pratt-parser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", - "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", - "dev": true, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/jsdom": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-19.0.0.tgz", - "integrity": "sha512-RYAyjCbxy/vri/CfnjUWJQQtZ3LKlLnDqj+9XLNnJPgEGeirZs3hllKR20re8LUZ6o1b1X4Jat+Qd26zmP41+A==", - "dev": true, - "dependencies": { - "abab": "^2.0.5", - "acorn": "^8.5.0", - "acorn-globals": "^6.0.0", - "cssom": "^0.5.0", - "cssstyle": "^2.3.0", - "data-urls": "^3.0.1", - "decimal.js": "^10.3.1", - "domexception": "^4.0.0", - "escodegen": "^2.0.0", - "form-data": "^4.0.0", - "html-encoding-sniffer": "^3.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^3.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^2.0.0", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^10.0.0", - "ws": "^8.2.3", - "xml-name-validator": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsdom/node_modules/form-data": { + "node_modules/jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "dev": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "argparse": "^1.0.7", + "esprima": "^4.0.0" }, - "engines": { - "node": ">= 6" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsdom/node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", "dev": true }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, "bin": { "jsesc": "bin/jsesc" }, @@ -15487,16 +10800,13 @@ "dev": true }, "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz", + "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, "node_modules/json-schema-traverse": { "version": "1.0.0", @@ -15510,16 +10820,11 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true - }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, "bin": { "json5": "lib/cli.js" }, @@ -15528,16 +10833,15 @@ } }, "node_modules/jsonc-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.1.0.tgz", - "integrity": "sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", "dev": true }, "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, "dependencies": { "universalify": "^2.0.0" }, @@ -15554,31 +10858,136 @@ "node >= 0.2.0" ] }, - "node_modules/jsprim": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", - "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", + "node_modules/karma": { + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.3.tgz", + "integrity": "sha512-LuucC/RE92tJ8mlCwqEoRWXP38UMAqpnq98vktmS9SznSoUPPUJQbc91dHcxcunROvfQjdORVA/YFviH+Xci9Q==", + "dev": true, + "dependencies": { + "@colors/colors": "1.5.0", + "body-parser": "^1.19.0", + "braces": "^3.0.2", + "chokidar": "^3.5.1", + "connect": "^3.7.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.1", + "glob": "^7.1.7", + "graceful-fs": "^4.2.6", + "http-proxy": "^1.18.1", + "isbinaryfile": "^4.0.8", + "lodash": "^4.17.21", + "log4js": "^6.4.1", + "mime": "^2.5.2", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.5", + "qjobs": "^1.2.0", + "range-parser": "^1.2.1", + "rimraf": "^3.0.2", + "socket.io": "^4.7.2", + "source-map": "^0.6.1", + "tmp": "^0.2.1", + "ua-parser-js": "^0.7.30", + "yargs": "^16.1.1" + }, + "bin": { + "karma": "bin/karma" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/karma-chrome-launcher": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz", + "integrity": "sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q==", "dev": true, - "engines": [ - "node >=0.6.0" - ], "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" + "which": "^1.2.1" } }, - "node_modules/jstransformer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", - "integrity": "sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==", + "node_modules/karma-chrome-launcher/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/karma-coverage": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.2.1.tgz", + "integrity": "sha512-yj7hbequkQP2qOSb20GuNSIyE//PgJWHwC2IydLE6XRtsnaflv+/OSGNssPjobYUlhVVagy99TQpqUt3vAUG7A==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.1", + "istanbul-reports": "^3.0.5", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/karma-coverage/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/karma-coverage/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/karma-jasmine": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-5.1.0.tgz", + "integrity": "sha512-i/zQLFrfEpRyQoJF9fsCdTMOF5c2dK7C7OmsuKg2D0YSsuZSfQDiLuaiktbuio6F2wiCsZSnSnieIQ0ant/uzQ==", "dev": true, "dependencies": { - "is-promise": "^2.0.0", - "promise": "^7.0.1" + "jasmine-core": "^4.1.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "karma": "^6.0.0" + } + }, + "node_modules/karma-jasmine-html-reporter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-2.1.0.tgz", + "integrity": "sha512-sPQE1+nlsn6Hwb5t+HHwyy0A1FNCVKuL1192b+XNauMYWThz2kweiBVW1DqloRpVvZIJkIoHVB7XRpK78n1xbQ==", + "dev": true, + "peerDependencies": { + "jasmine-core": "^4.0.0 || ^5.0.0", + "karma": "^6.0.0", + "karma-jasmine": "^5.0.0" } }, + "node_modules/karma-jasmine/node_modules/jasmine-core": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.6.0.tgz", + "integrity": "sha512-O236+gd0ZXS8YAjFx8xKaJ94/erqUliEkJTDedyE7iHvv4ZVqi+q+8acJxu05/WJDKm512EUNn809In37nWlAQ==", + "dev": true + }, "node_modules/karma-source-map-support": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", @@ -15588,6 +10997,154 @@ "source-map-support": "^0.5.5" } }, + "node_modules/karma/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/karma/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/karma/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/karma/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/karma/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/karma/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/karma/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/karma/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/karma/node_modules/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "dev": true, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/karma/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/karma/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/karma/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/katex": { "version": "0.16.11", "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.11.tgz", @@ -15596,6 +11153,7 @@ "https://opencollective.com/katex", "https://github.com/sponsors/katex" ], + "optional": true, "dependencies": { "commander": "^8.3.0" }, @@ -15607,6 +11165,7 @@ "version": "8.3.0", "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "optional": true, "engines": { "node": ">= 12" } @@ -15623,7 +11182,8 @@ "node_modules/khroma": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", - "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==" + "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==", + "optional": true }, "node_modules/kind-of": { "version": "6.0.3", @@ -15634,48 +11194,48 @@ "node": ">=0.10.0" } }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", + "optional": true + }, + "node_modules/langium": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/langium/-/langium-3.0.0.tgz", + "integrity": "sha512-+Ez9EoiByeoTu/2BXmEaZ06iPNXM6thWJp02KfBO/raSMyCJ4jw7AkWWa+zBCTm0+Tw1Fj9FOxdqSskyN5nAwg==", + "optional": true, + "dependencies": { + "chevrotain": "~11.0.3", + "chevrotain-allstar": "~0.3.0", + "vscode-languageserver": "~9.0.1", + "vscode-languageserver-textdocument": "~1.0.11", + "vscode-uri": "~3.0.8" + }, "engines": { - "node": ">=6" + "node": ">=16.0.0" } }, - "node_modules/klona": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", - "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "node_modules/launch-editor": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.1.tgz", + "integrity": "sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw==", "dev": true, - "engines": { - "node": ">= 8" + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" } }, - "node_modules/known-css-properties": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.25.0.tgz", - "integrity": "sha512-b0/9J1O9Jcyik1GC6KC42hJ41jKwdO/Mq8Mdo5sYN+IuRTXs2YFHZC3kZSx6ueusqa95x3wLYe/ytKjbAfGixA==", - "dev": true - }, "node_modules/layout-base": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", - "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==" - }, - "node_modules/lazy-ass": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", - "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==", - "dev": true, - "engines": { - "node": "> 0.8" - } + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", + "optional": true }, "node_modules/less": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz", - "integrity": "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", + "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", "dev": true, "dependencies": { "copy-anything": "^2.0.1", @@ -15699,23 +11259,29 @@ } }, "node_modules/less-loader": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.0.0.tgz", - "integrity": "sha512-9+LOWWjuoectIEx3zrfN83NAGxSUB5pWEabbbidVQVgZhN+wN68pOvuyirVlH1IK4VT1f3TmlyvAnCXh8O5KEw==", + "version": "12.2.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-12.2.0.tgz", + "integrity": "sha512-MYUxjSQSBUQmowc0l5nPieOYwMzGPUaTzB6inNW/bdPEG9zOL3eAAD1Qw5ZxSPk7we5dMojHwNODYMV1hq4EVg==", "dev": true, - "dependencies": { - "klona": "^2.0.4" - }, "engines": { - "node": ">= 14.15.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { + "@rspack/core": "0.x || 1.x", "less": "^3.5.0 || ^4.0.0", "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } } }, "node_modules/less/node_modules/make-dir": { @@ -15775,15 +11341,6 @@ "node": ">=0.10.0" } }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -15814,45 +11371,45 @@ } } }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, - "node_modules/listr2": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", - "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", + "node_modules/lmdb": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-3.0.8.tgz", + "integrity": "sha512-9rp8JT4jPhCRJUL7vRARa2N06OLSYzLwQsEkhC6Qu5XbcLyM/XBLMzDlgS/K7l7c5CdURLdDk9uE+hPFIogHTQ==", "dev": true, + "hasInstallScript": true, "dependencies": { - "cli-truncate": "^2.1.0", - "colorette": "^2.0.16", - "log-update": "^4.0.0", - "p-map": "^4.0.0", - "rfdc": "^1.3.0", - "rxjs": "^7.5.1", - "through": "^2.3.8", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=10.0.0" + "msgpackr": "^1.9.9", + "node-addon-api": "^6.1.0", + "node-gyp-build-optional-packages": "5.1.1", + "ordered-binary": "^1.4.1", + "weak-lru-cache": "^1.2.2" }, - "peerDependencies": { - "enquirer": ">= 2.3.0 < 3" + "bin": { + "download-lmdb-prebuilds": "bin/download-prebuilds.js" }, - "peerDependenciesMeta": { - "enquirer": { - "optional": true - } + "optionalDependencies": { + "@lmdb/lmdb-darwin-arm64": "3.0.8", + "@lmdb/lmdb-darwin-x64": "3.0.8", + "@lmdb/lmdb-linux-arm": "3.0.8", + "@lmdb/lmdb-linux-arm64": "3.0.8", + "@lmdb/lmdb-linux-x64": "3.0.8", + "@lmdb/lmdb-win32-x64": "3.0.8" } }, - "node_modules/listr2/node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true - }, "node_modules/loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", @@ -15863,14 +11420,30 @@ } }, "node_modules/loader-utils": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.0.tgz", - "integrity": "sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", "dev": true, "engines": { "node": ">= 12.13.0" } }, + "node_modules/local-pkg": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz", + "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==", + "optional": true, + "dependencies": { + "mlly": "^1.4.2", + "pkg-types": "^1.0.3" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -15886,54 +11459,57 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true }, "node_modules/lodash-es": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" }, + "node_modules/lodash.castarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", + "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", + "dev": true + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "dev": true }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "dev": true + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", "dev": true }, + "node_modules/lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", - "dev": true - }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "dev": true - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" @@ -15949,7 +11525,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -15964,7 +11539,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -15980,7 +11554,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -15991,14 +11564,12 @@ "node_modules/log-symbols/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/log-symbols/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -16007,7 +11578,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -16015,259 +11585,55 @@ "node": ">=8" } }, - "node_modules/log-update": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", - "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.3.0", - "cli-cursor": "^3.1.0", - "slice-ansi": "^4.0.0", - "wrap-ansi": "^6.2.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/log-update/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/log-update/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/log-update/node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/log-update/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "node_modules/log4js": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", + "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", "dev": true, "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", + "rfdc": "^1.3.0", + "streamroller": "^3.1.5" }, "engines": { - "node": ">=8" + "node": ">=8.0" } }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/magic-string": { - "version": "0.26.2", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.2.tgz", - "integrity": "sha512-NzzlXpclt5zAbmo6h6jNc8zl2gNRGHvmsZW4IvZhTC4W7k4OlLP+S5YLussa/r3ixNT66KOQfNORlXHSOy/X4A==", - "dependencies": { - "sourcemap-codec": "^1.4.8" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/make-fetch-happen": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", - "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", - "dev": true, - "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^16.1.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^2.0.3", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^9.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dev": true, "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/map-obj": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", - "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/marked": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.2.tgz", - "integrity": "sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q==", - "bin": { - "marked": "bin/marked.js" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/material-design-icons-iconfont": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/material-design-icons-iconfont/-/material-design-icons-iconfont-6.7.0.tgz", - "integrity": "sha512-lSj71DgVv20kO0kGbs42icDzbRot61gEDBLQACzkUuznRQBUYmbxzEkGU6dNBb5fRWHMaScYlAXX96HQ4/cJWA==" - }, - "node_modules/mathml-tag-names": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz", - "integrity": "sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "dev": true, + "yallist": "^3.0.2" + } + }, + "node_modules/luxon": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", + "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==", "engines": { - "node": ">= 0.6" + "node": ">=12" } }, - "node_modules/memfs": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", - "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "node_modules/magic-string": { + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", "dev": true, "dependencies": { - "fs-monkey": "^1.0.4" - }, - "engines": { - "node": ">= 4.0.0" + "@jridgewell/sourcemap-codec": "^1.4.15" } }, - "node_modules/meow": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", - "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, "dependencies": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize": "^1.2.0", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^3.0.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.18.0", - "yargs-parser": "^20.2.3" + "semver": "^7.5.3" }, "engines": { "node": ">=10" @@ -16276,79 +11642,67 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/meow/node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/meow/node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "node_modules/make-fetch-happen": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz", + "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "proc-log": "^4.2.0", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" }, "engines": { - "node": ">=10" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/meow/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" + "node_modules/marked": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.2.tgz", + "integrity": "sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q==", + "peer": true, + "bin": { + "marked": "bin/marked.js" }, "engines": { - "node": ">=10" + "node": ">= 18" } }, - "node_modules/meow/node_modules/normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "dev": true, - "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - }, "engines": { - "node": ">=10" + "node": ">= 0.6" } }, - "node_modules/meow/node_modules/type-fest": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", - "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "node_modules/memfs": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.9.2.tgz", + "integrity": "sha512-f16coDZlTG1jskq3mxarwB+fGRrd0uXWt+o1WIhRfOwbXQZqUDsTVxQBFK9JjRQHblg8eAG2JSbprDXKjc7ijQ==", "dev": true, + "dependencies": { + "@jsonjoy.com/json-pack": "^1.0.3", + "@jsonjoy.com/util": "^1.1.2", + "sonic-forest": "^1.0.0", + "tslib": "^2.0.0" + }, "engines": { - "node": ">=10" + "node": ">= 4.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/meow/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "engines": { - "node": ">=10" + "type": "github", + "url": "https://github.com/sponsors/streamich" } }, "node_modules/merge-descriptors": { @@ -16373,26 +11727,42 @@ } }, "node_modules/mermaid": { - "version": "9.4.3", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-9.4.3.tgz", - "integrity": "sha512-TLkQEtqhRSuEHSE34lh5bCa94KATCyluAXmFnNI2PRZwOpXFeqiJWwZl+d2CcemE1RS6QbbueSSq9QIg8Uxcyw==", + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.3.0.tgz", + "integrity": "sha512-fFmf2gRXLtlGzug4wpIGN+rQdZ30M8IZEB1D3eZkXNqC7puhqeURBcD/9tbwXsqBO+A6Nzzo3MSSepmnw5xSeg==", + "optional": true, "dependencies": { - "@braintree/sanitize-url": "^6.0.0", - "cytoscape": "^3.23.0", + "@braintree/sanitize-url": "^7.0.1", + "@iconify/utils": "^2.1.32", + "@mermaid-js/parser": "^0.3.0", + "cytoscape": "^3.29.2", "cytoscape-cose-bilkent": "^4.1.0", - "cytoscape-fcose": "^2.1.0", - "d3": "^7.4.0", - "dagre-d3-es": "7.0.9", - "dayjs": "^1.11.7", - "dompurify": "2.4.3", - "elkjs": "^0.8.2", - "khroma": "^2.0.0", + "cytoscape-fcose": "^2.2.0", + "d3": "^7.9.0", + "d3-sankey": "^0.12.3", + "dagre-d3-es": "7.0.10", + "dayjs": "^1.11.10", + "dompurify": "^3.0.11 <3.1.7", + "katex": "^0.16.9", + "khroma": "^2.1.0", "lodash-es": "^4.17.21", - "non-layered-tidy-tree-layout": "^2.0.2", - "stylis": "^4.1.2", + "marked": "^13.0.2", + "roughjs": "^4.6.6", + "stylis": "^4.3.1", "ts-dedent": "^2.2.0", - "uuid": "^9.0.0", - "web-worker": "^1.2.0" + "uuid": "^9.0.1" + } + }, + "node_modules/mermaid/node_modules/marked": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/marked/-/marked-13.0.3.tgz", + "integrity": "sha512-rqRix3/TWzE9rIoFGIn8JmsVfhiuC8VIQ8IdX5TfzmeBucdY05/0UlzKaw0eVtpcN/OdVFpBk7CjKGo9iHJ/zA==", + "optional": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" } }, "node_modules/mermaid/node_modules/uuid": { @@ -16403,6 +11773,7 @@ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], + "optional": true, "bin": { "uuid": "dist/bin/uuid" } @@ -16417,27 +11788,40 @@ } }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "dependencies": { - "braces": "^3.0.3", + "braces": "^3.0.2", "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" } }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/mime": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", - "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, "bin": { "mime": "cli.js" }, "engines": { - "node": ">=10.0.0" + "node": ">=4.0.0" } }, "node_modules/mime-db": { @@ -16465,49 +11849,18 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, "engines": { "node": ">=6" } }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/mini-css-extract-plugin": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz", - "integrity": "sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg==", - "dev": true, - "dependencies": { - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.0.tgz", + "integrity": "sha512-Zs1YsZVfemekSZG+44vBsYTLQORkPMwnlv+aehcxK/NLKC+EGhDB39/YePYYqx/sTk6NnYpuqikhSn7+JIevTA==", "dev": true, "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" }, "engines": { "node": ">= 12.13.0" @@ -16515,1023 +11868,778 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "node_modules/minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minimist-options": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", - "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", - "dev": true, - "dependencies": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-fetch": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", - "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", - "dev": true, - "dependencies": { - "minipass": "^3.1.6", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-json-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", - "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", - "dev": true, - "dependencies": { - "jsonparse": "^1.3.1", - "minipass": "^3.0.0" - } - }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" }, - "engines": { - "node": ">= 8" + "peerDependencies": { + "webpack": "^5.0.0" } }, - "node_modules/minizlib/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", "dev": true }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" + "node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dependencies": { + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/moment": { - "version": "2.30.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", - "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, - "engines": { - "node": "*" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/mri": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", - "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", - "dev": true, + "node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "engines": { - "node": ">=4" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/multer": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4.tgz", - "integrity": "sha512-2wY2+xD4udX612aMqMcB8Ws2Voq6NIUPEtD1be6m411T4uDH/VtL9i//xvcyFlTVfRdaBsk7hV5tgrGQqhuBiw==", - "deprecated": "Multer 1.x is affected by CVE-2022-24434. This is fixed in v1.4.4-lts.1 which drops support for versions of Node.js before 6. Please upgrade to at least Node.js 6 and version 1.4.4-lts.1 of Multer. If you need support for older versions of Node.js, we are open to accepting patches that would fix the CVE on the main 1.x release line, whilst maintaining compatibility with Node.js 0.10.", + "node_modules/minipass-collect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", "dev": true, "dependencies": { - "append-field": "^1.0.0", - "busboy": "^0.2.11", - "concat-stream": "^1.5.2", - "mkdirp": "^0.5.4", - "object-assign": "^4.1.1", - "on-finished": "^2.3.0", - "type-is": "^1.6.4", - "xtend": "^4.0.0" + "minipass": "^7.0.3" }, "engines": { - "node": ">= 0.10.0" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/multer/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "node_modules/minipass-fetch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz", + "integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==", "dev": true, "dependencies": { - "minimist": "^1.2.6" + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" }, - "bin": { - "mkdirp": "bin/cmd.js" + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" } }, - "node_modules/multicast-dns": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", "dev": true, "dependencies": { - "dns-packet": "^5.2.2", - "thunky": "^1.0.2" + "minipass": "^3.0.0" }, - "bin": { - "multicast-dns": "cli.js" + "engines": { + "node": ">= 8" } }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" + "dependencies": { + "yallist": "^4.0.0" }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": ">=8" } }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "node_modules/minipass-flush/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, - "node_modules/needle": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", - "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", + "node_modules/minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", "dev": true, - "optional": true, "dependencies": { - "iconv-lite": "^0.6.3", - "sax": "^1.2.4" - }, - "bin": { - "needle": "bin/needle" - }, - "engines": { - "node": ">= 4.4.x" + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" } }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "node_modules/minipass-json-stream/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=8" } }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "node_modules/minipass-json-stream/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, - "node_modules/ngx-markdown": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/ngx-markdown/-/ngx-markdown-14.0.1.tgz", - "integrity": "sha512-y5CY4e0QM0uR6+MvU1rnh1Ks+rku14309kVVojyXLcWl4zlrt8VAYCcf/+A+8z/IDOaz38yTrxNBnvYDJzNzYA==", + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, "dependencies": { - "@types/marked": "^4.0.3", - "clipboard": "^2.0.11", - "emoji-toolkit": "^6.6.0", - "katex": "^0.16.0", - "marked": "^4.0.17", - "mermaid": "^9.1.2", - "prismjs": "^1.28.0", - "tslib": "^2.3.0" - }, - "peerDependencies": { - "@angular/common": "^14.0.0", - "@angular/core": "^14.0.0", - "@angular/platform-browser": "^14.0.0", - "rxjs": "^6.5.3 || ^7.4.0", - "zone.js": "^0.11.4" - } - }, - "node_modules/ngx-markdown/node_modules/marked": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", - "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", - "bin": { - "marked": "bin/marked.js" + "minipass": "^3.0.0" }, "engines": { - "node": ">= 12" + "node": ">=8" } }, - "node_modules/nice-napi": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", - "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "!win32" - ], "dependencies": { - "node-addon-api": "^3.0.0", - "node-gyp-build": "^4.2.2" + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/node-addon-api": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", - "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "node_modules/minipass-pipeline/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, - "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, "engines": { - "node": ">= 6.13.0" + "node": ">=8" } }, - "node_modules/node-gyp": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.1.tgz", - "integrity": "sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==", + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^10.0.3", - "nopt": "^6.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" + "yallist": "^4.0.0" }, "engines": { - "node": "^12.13 || ^14.13 || >=16" - } - }, - "node_modules/node-gyp-build": { - "version": "4.8.1", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz", - "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==", - "dev": true, - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" + "node": ">=8" } }, - "node_modules/node-gyp/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } + "node_modules/minipass-sized/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, - "node_modules/node-gyp/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" }, "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">= 8" } }, - "node_modules/node-gyp/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "yallist": "^4.0.0" }, "engines": { - "node": "*" + "node": ">=8" } }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, - "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" - }, - "node_modules/non-layered-tidy-tree-layout": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/non-layered-tidy-tree-layout/-/non-layered-tidy-tree-layout-2.0.2.tgz", - "integrity": "sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==" - }, - "node_modules/nopt": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", - "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "dependencies": { - "abbrev": "^1.0.0" + "minimist": "^1.2.6" }, "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "mkdirp": "bin/cmd.js" } }, - "node_modules/normalize-package-data": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-4.0.1.tgz", - "integrity": "sha512-EBk5QKKuocMJhB3BILuKhmaPjI8vNRSpIfO9woLC6NyHVkKKdVEdAO1mrT0ZfxNR1lKwCcTkuZfmGIFdizZ8Pg==", - "dev": true, + "node_modules/mlly": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.2.tgz", + "integrity": "sha512-tN3dvVHYVz4DhSXinXIk7u9syPYaJvio118uomkovAtWBT+RdbP6Lfh/5Lvo519YMmwBafwlh20IPTXIStscpA==", + "optional": true, "dependencies": { - "hosted-git-info": "^5.0.0", - "is-core-module": "^2.8.1", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "acorn": "^8.12.1", + "pathe": "^1.1.2", + "pkg-types": "^1.2.0", + "ufo": "^1.5.4" } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "node_modules/mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "devOptional": true + }, + "node_modules/msgpackr": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.10.2.tgz", + "integrity": "sha512-L60rsPynBvNE+8BWipKKZ9jHcSGbtyJYIwjRq0VrIvQ08cRjntGXJYW/tmciZ2IHWIY8WEW32Qa2xbh5+SKBZA==", "dev": true, - "engines": { - "node": ">=0.10.0" + "optionalDependencies": { + "msgpackr-extract": "^3.0.2" } }, - "node_modules/npm-bundled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", - "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", + "node_modules/msgpackr-extract": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.2.tgz", + "integrity": "sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A==", "dev": true, + "hasInstallScript": true, + "optional": true, "dependencies": { - "npm-normalize-package-bin": "^1.0.1" + "node-gyp-build-optional-packages": "5.0.7" + }, + "bin": { + "download-msgpackr-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.2" } }, - "node_modules/npm-install-checks": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-5.0.0.tgz", - "integrity": "sha512-65lUsMI8ztHCxFz5ckCEC44DRvEGdZX5usQFriauxHEwt7upv1FKaQEmAtU0YnOAdwuNWCmk64xYiQABNrEyLA==", + "node_modules/msgpackr-extract/node_modules/node-gyp-build-optional-packages": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz", + "integrity": "sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==", + "dev": true, + "optional": true, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", "dev": true, "dependencies": { - "semver": "^7.1.1" + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "bin": { + "multicast-dns": "cli.js" } }, - "node_modules/npm-normalize-package-bin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", - "dev": true + "node_modules/mute-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, - "node_modules/npm-package-arg": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.0.tgz", - "integrity": "sha512-4J0GL+u2Nh6OnhvUKXRr2ZMG4lR8qtLp+kv7UiV00Y+nGiSxtttCyIRHCt5L5BNkXQld/RceYItau3MDOoGiBw==", + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", "dev": true, "dependencies": { - "hosted-git-info": "^5.0.0", - "proc-log": "^2.0.1", - "semver": "^7.3.5", - "validate-npm-package-name": "^4.0.0" + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/npm-packlist": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-5.1.3.tgz", - "integrity": "sha512-263/0NGrn32YFYi4J533qzrQ/krmmrWwhKkzwTuM4f/07ug51odoaNjUexxO4vxlzURHcmYMH1QjvHjsNDKLVg==", + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/needle": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", + "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", "dev": true, + "optional": true, "dependencies": { - "glob": "^8.0.1", - "ignore-walk": "^5.0.1", - "npm-bundled": "^2.0.0", - "npm-normalize-package-bin": "^2.0.0" + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" }, "bin": { - "npm-packlist": "bin/index.js" + "needle": "bin/needle" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">= 4.4.x" } }, - "node_modules/npm-packlist/node_modules/npm-bundled": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-2.0.1.tgz", - "integrity": "sha512-gZLxXdjEzE/+mOstGDqR6b0EkhJ+kM6fxM6vUuckuctuVPh80Q6pw/rSZj9s4Gex9GxWtIicO1pc8DB9KZWudw==", + "node_modules/needle/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, + "optional": true, "dependencies": { - "npm-normalize-package-bin": "^2.0.0" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=0.10.0" } }, - "node_modules/npm-packlist/node_modules/npm-normalize-package-bin": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", - "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "dev": true, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">= 0.6" } }, - "node_modules/npm-pick-manifest": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-7.0.1.tgz", - "integrity": "sha512-IA8+tuv8KujbsbLQvselW2XQgmXWS47t3CB0ZrzsRZ82DbDfkcFunOaPm4X7qNuhMfq+FmV7hQT4iFVpHqV7mg==", - "dev": true, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/ng-apexcharts": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/ng-apexcharts/-/ng-apexcharts-1.11.0.tgz", + "integrity": "sha512-bzZ2qMYpJJ1V/Yfp9eC5y7BuxrlZx4fc9ev9pNHW8qEs5B0yE5yW25WrLhoGTYsfeFZfiADWeAmZkceEiihpFw==", "dependencies": { - "npm-install-checks": "^5.0.0", - "npm-normalize-package-bin": "^1.0.1", - "npm-package-arg": "^9.0.0", - "semver": "^7.3.5" + "tslib": "^2.0.0" }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "peerDependencies": { + "@angular/common": "^18.0.1", + "@angular/core": "^18.0.1", + "apexcharts": "^3.49.1", + "rxjs": "^6.5.5 || ^7.4.0" } }, - "node_modules/npm-registry-fetch": { - "version": "13.3.1", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-13.3.1.tgz", - "integrity": "sha512-eukJPi++DKRTjSBRcDZSDDsGqRK3ehbxfFUcgaRd0Yp6kRwOwh2WVn0r+8rMB4nnuzvAk6rQVzl6K5CkYOmnvw==", - "dev": true, + "node_modules/ngx-markdown": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/ngx-markdown/-/ngx-markdown-18.1.0.tgz", + "integrity": "sha512-n4HFSm5oqVMXFuD+WXIVkI6NyxD8Oubr4B3c9U1J7Ptr6t9DVnkNBax3yxWc+8Wli+FXTuGEnDXzB3sp7E9paA==", "dependencies": { - "make-fetch-happen": "^10.0.6", - "minipass": "^3.1.6", - "minipass-fetch": "^2.0.3", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.1.2", - "npm-package-arg": "^9.0.1", - "proc-log": "^2.0.0" + "tslib": "^2.3.0" }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "optionalDependencies": { + "clipboard": "^2.0.11", + "emoji-toolkit": ">= 8.0.0 < 10.0.0", + "katex": "^0.16.0", + "mermaid": ">= 10.6.0 < 12.0.0", + "prismjs": "^1.28.0" + }, + "peerDependencies": { + "@angular/common": "^18.0.0", + "@angular/core": "^18.0.0", + "@angular/platform-browser": "^18.0.0", + "marked": ">= 9.0.0 < 13.0.0", + "rxjs": "^6.5.3 || ^7.4.0", + "zone.js": "~0.14.0" } }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, + "node_modules/ngx-quill": { + "version": "26.0.1", + "resolved": "https://registry.npmjs.org/ngx-quill/-/ngx-quill-26.0.1.tgz", + "integrity": "sha512-jiG4YKrGRdtv3g3jno36N5nHNuyCnOmGcHWnvadNy/w/T+MTFEkjyIN4if9KVPWqXmaXkC3/07njNuWpCJRtSQ==", "dependencies": { - "path-key": "^3.0.0" + "tslib": "^2.3.0" }, "engines": { - "node": ">=8" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + }, + "peerDependencies": { + "@angular/core": "^18.0.0", + "quill": "^2.0.0", + "rxjs": "^7.0.0" } }, - "node_modules/npmlog": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "deprecated": "This package is no longer supported.", + "node_modules/nice-napi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", + "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "!win32" + ], "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node-addon-api": "^3.0.0", + "node-gyp-build": "^4.2.2" } }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "node_modules/nice-napi/node_modules/node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", "dev": true, - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } + "optional": true }, - "node_modules/nwsapi": { - "version": "2.2.12", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.12.tgz", - "integrity": "sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==", + "node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", "dev": true }, - "node_modules/nx": { - "version": "14.8.9", - "resolved": "https://registry.npmjs.org/nx/-/nx-14.8.9.tgz", - "integrity": "sha512-X29mxovtXkrqcYNndTNMUOrtO3tkSZF0GkdsQ16kCxo4YIqUVVOpM7IzZYx+JxO6fVDFMlK7eGU2C2lTHz/MSQ==", + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", "dev": true, - "hasInstallScript": true, - "dependencies": { - "@nrwl/cli": "14.8.9", - "@nrwl/tao": "14.8.9", - "@parcel/watcher": "2.0.4", - "@yarnpkg/lockfile": "^1.1.0", - "@yarnpkg/parsers": "^3.0.0-rc.18", - "@zkochan/js-yaml": "0.0.6", - "axios": "^1.0.0", - "chalk": "4.1.0", - "chokidar": "^3.5.1", - "cli-cursor": "3.1.0", - "cli-spinners": "2.6.1", - "cliui": "^7.0.2", - "dotenv": "~10.0.0", - "enquirer": "~2.3.6", - "fast-glob": "3.2.7", - "figures": "3.2.0", - "flat": "^5.0.2", - "fs-extra": "^10.1.0", - "glob": "7.1.4", - "ignore": "^5.0.4", - "js-yaml": "4.1.0", - "jsonc-parser": "3.2.0", - "minimatch": "3.0.5", - "npm-run-path": "^4.0.1", - "open": "^8.4.0", - "semver": "7.3.4", - "string-width": "^4.2.3", - "strong-log-transformer": "^2.1.0", - "tar-stream": "~2.2.0", - "tmp": "~0.2.1", - "tsconfig-paths": "^3.9.0", - "tslib": "^2.3.0", - "v8-compile-cache": "2.3.0", - "yargs": "^17.4.0", - "yargs-parser": "21.0.1" - }, - "bin": { - "nx": "bin/nx.js" - }, - "peerDependencies": { - "@swc-node/register": "^1.4.2", - "@swc/core": "^1.2.173" - }, - "peerDependenciesMeta": { - "@swc-node/register": { - "optional": true - }, - "@swc/core": { - "optional": true - } + "engines": { + "node": ">= 6.13.0" } }, - "node_modules/nx/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/node-gyp": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.1.0.tgz", + "integrity": "sha512-B4J5M1cABxPc5PwfjhbV5hoy2DP9p8lFXASnEN6hugXOa61416tnTZ29x9sSwAd0o99XNIcpvDDy1swAExsVKA==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^13.0.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^4.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/nx/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/node-gyp-build": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz", + "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==", "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" } }, - "node_modules/nx/node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "node_modules/node-gyp-build-optional-packages": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.1.1.tgz", + "integrity": "sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" + "detect-libc": "^2.0.1" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" } }, - "node_modules/nx/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/node-gyp/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, "engines": { - "node": ">=7.0.0" + "node": ">=16" } }, - "node_modules/nx/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/nx/node_modules/dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "node_modules/node-gyp/node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", "dev": true, "engines": { - "node": ">=10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "node_modules/node-gyp/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", "dev": true, "dependencies": { - "ansi-colors": "^4.1.1" + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" }, "engines": { - "node": ">=8.6" + "node": "^16.13.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "node_modules/nopt": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", + "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", "dev": true, "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" }, "engines": { - "node": ">=8" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "node_modules/normalize-package-data": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.1.tgz", + "integrity": "sha512-6rvCfeRW+OEZagAB4lMLSNuTNYZWLVtKccK79VSTf//yTY5VOCgcpH80O+bZK8Neps7pUnd5G+QlMg1yV/2iZQ==", "dev": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "hosted-git-info": "^7.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" }, "engines": { - "node": "*" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/nx/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/nx/node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, - "node_modules/nx/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/npm-bundled": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.1.tgz", + "integrity": "sha512-+AvaheE/ww1JEwRHOrn4WHNzOxGtVp+adrg2AeZS/7KuxGUYFuBta98wYpfHBbJp6Tg6j1NKSEVHNcfZzJHQwQ==", "dev": true, "dependencies": { - "yallist": "^4.0.0" + "npm-normalize-package-bin": "^3.0.0" }, "engines": { - "node": ">=10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", + "node_modules/npm-install-checks": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", + "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "semver": "^7.1.1" }, "engines": { - "node": "*" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, "engines": { - "node": ">=10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/npm-package-arg": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.2.tgz", + "integrity": "sha512-IGN0IAwmhDJwy13Wc8k+4PEbTPhpJnMtfR53ZbOyjkvmEcLS4nCwp6mvMWjS5sUjeiW3mpx6cHmuhKEu9XmcQw==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "hosted-git-info": "^7.0.0", + "proc-log": "^4.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" }, "engines": { - "node": ">=8" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "node_modules/npm-packlist": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.2.tgz", + "integrity": "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==", "dev": true, + "dependencies": { + "ignore-walk": "^6.0.4" + }, "engines": { - "node": ">=0.10.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "node_modules/npm-pick-manifest": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.0.1.tgz", + "integrity": "sha512-Udm1f0l2nXb3wxDpKjfohwgdFUSV50UVwzEIpDXVsbDMXVIEF81a/i0UhuQbhrPMMmdiq3+YMFLFIRVLs3hxQw==", "dev": true, - "engines": { - "node": ">= 0.4" + "dependencies": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^11.0.0", + "semver": "^7.3.5" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "node_modules/npm-registry-fetch": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-17.0.1.tgz", + "integrity": "sha512-fLu9MTdZTlJAHUek/VLklE6EpIiP3VZpTiuN7OOMCt2Sd67NCpSEetMaxHHEZiZxllp8ZLsUpvbEszqTFEc+wA==", "dev": true, + "dependencies": { + "@npmcli/redact": "^2.0.0", + "make-fetch-happen": "^13.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^11.0.0", + "proc-log": "^4.0.0" + }, "engines": { - "node": ">= 0.4" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" + "path-key": "^3.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/object.fromentries": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", - "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dev": true, "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" + "boolbase": "^1.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "node_modules/object.groupby": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", - "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2" - }, "engines": { - "node": ">= 0.4" + "node": ">=0.10.0" } }, - "node_modules/object.values": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", - "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, "engines": { - "node": ">= 0.4" - }, + "node": ">= 6" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -17542,12 +12650,6 @@ "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", "dev": true }, - "node_modules/octicons": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/octicons/-/octicons-4.4.0.tgz", - "integrity": "sha512-I/NKRKeHEbF+8y6VmJw9pcQ6IBXDuu+F8mJYN10dpaZrl95MOxn+9xRiss1SYkIZ5+2p1xbUl7GuWd+8mNZb8Q==", - "dev": true - }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -17581,7 +12683,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, "dependencies": { "mimic-fn": "^2.1.0" }, @@ -17593,9 +12694,9 @@ } }, "node_modules/open": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", - "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", "dev": true, "dependencies": { "define-lazy-prop": "^2.0.0", @@ -17630,7 +12731,6 @@ "version": "5.4.1", "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "dev": true, "dependencies": { "bl": "^4.1.0", "chalk": "^4.1.0", @@ -17653,7 +12753,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -17668,7 +12767,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -17684,7 +12782,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -17695,14 +12792,12 @@ "node_modules/ora/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/ora/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -17711,7 +12806,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -17719,6 +12813,12 @@ "node": ">=8" } }, + "node_modules/ordered-binary": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.5.1.tgz", + "integrity": "sha512-5VyHfHY3cd0iza71JepYG50My+YUbrFtGoUz2ooEydPyPM7Aai/JW098juLr+RG6+rDJuzNNTsEQu2DZa1A41A==", + "dev": true + }, "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -17728,22 +12828,16 @@ "node": ">=0.10.0" } }, - "node_modules/ospath": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", - "integrity": "sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==", - "dev": true - }, "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "dependencies": { - "yocto-queue": "^0.1.0" + "p-try": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -17757,23 +12851,8 @@ "dependencies": { "p-limit": "^2.2.0" }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-locate/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=8" } }, "node_modules/p-map": { @@ -17792,16 +12871,20 @@ } }, "node_modules/p-retry": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.0.tgz", + "integrity": "sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==", "dev": true, "dependencies": { - "@types/retry": "0.12.0", + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", "retry": "^0.13.1" }, "engines": { - "node": ">=8" + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-retry/node_modules/retry": { @@ -17822,57 +12905,52 @@ "node": ">=6" } }, - "node_modules/package-json-from-dist": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", - "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==" + "node_modules/package-manager-detector": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-0.2.2.tgz", + "integrity": "sha512-VgXbyrSNsml4eHWIvxxG/nTL4wgybMTXCV2Un/+yEc3aDKKU6nQBZjbeP3Pl3qm9Qg92X/1ng4ffvCeD/zwHgg==", + "optional": true }, "node_modules/pacote": { - "version": "13.6.1", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-13.6.1.tgz", - "integrity": "sha512-L+2BI1ougAPsFjXRyBhcKmfT016NscRFLv6Pz5EiNf1CCFJFU0pSKKQwsZTyAQB+sTuUL4TyFyp6J1Ork3dOqw==", - "dev": true, - "dependencies": { - "@npmcli/git": "^3.0.0", - "@npmcli/installed-package-contents": "^1.0.7", - "@npmcli/promise-spawn": "^3.0.0", - "@npmcli/run-script": "^4.1.0", - "cacache": "^16.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "infer-owner": "^1.0.4", - "minipass": "^3.1.6", - "mkdirp": "^1.0.4", - "npm-package-arg": "^9.0.0", - "npm-packlist": "^5.1.0", - "npm-pick-manifest": "^7.0.0", - "npm-registry-fetch": "^13.0.1", - "proc-log": "^2.0.0", + "version": "18.0.6", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-18.0.6.tgz", + "integrity": "sha512-+eK3G27SMwsB8kLIuj4h1FUhHtwiEUo21Tw8wNjmvdlpOEr613edv+8FUsTj/4F/VN5ywGE19X18N7CC2EJk6A==", + "dev": true, + "dependencies": { + "@npmcli/git": "^5.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/package-json": "^5.1.0", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^8.0.0", + "cacache": "^18.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^11.0.0", + "npm-packlist": "^8.0.0", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^17.0.0", + "proc-log": "^4.0.0", "promise-retry": "^2.0.1", - "read-package-json": "^5.0.0", - "read-package-json-fast": "^2.0.3", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", + "sigstore": "^2.2.0", + "ssri": "^10.0.0", "tar": "^6.1.11" }, "bin": { - "pacote": "lib/bin.js" + "pacote": "bin/index.js" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true + "node_modules/parchment": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/parchment/-/parchment-3.0.0.tgz", + "integrity": "sha512-HUrJFQ/StvgmXRcQ1ftY6VEZUq3jA2t9ncFN4F84J/vN0/FPpQF+8FKXb3l6fLces6q0uOHj6NJn+2xvZnxO6A==" }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, "dependencies": { "callsites": "^3.0.0" }, @@ -17880,24 +12958,10 @@ "node": ">=6" } }, - "node_modules/parse-imports": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/parse-imports/-/parse-imports-2.1.1.tgz", - "integrity": "sha512-TDT4HqzUiTMO1wJRwg/t/hYk8Wdp3iF/ToMIlAoVQfL1Xs/sTxq1dKWSMjMbQmIarfWKymOyly40+zmPHXMqCA==", - "dev": true, - "dependencies": { - "es-module-lexer": "^1.5.3", - "slashes": "^3.0.12" - }, - "engines": { - "node": ">= 18" - } - }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -17911,6 +12975,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse-json/node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, "node_modules/parse-node-version": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", @@ -17921,57 +12990,43 @@ } }, "node_modules/parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", - "optional": true - }, - "node_modules/parse5-html-rewriting-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-6.0.1.tgz", - "integrity": "sha512-vwLQzynJVEfUlURxgnf51yAJDQTtVpNyGD8tKi2Za7m+akukNHxCcUQMAa/mUGLhCeicFdpy7Tlvj8ZNKadprg==", - "dev": true, + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "devOptional": true, "dependencies": { - "parse5": "^6.0.1", - "parse5-sax-parser": "^6.0.1" + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/parse5-html-rewriting-stream/node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "node_modules/parse5-htmlparser2-tree-adapter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", - "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "node_modules/parse5-html-rewriting-stream": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.0.0.tgz", + "integrity": "sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg==", "dev": true, "dependencies": { - "parse5": "^6.0.1" + "entities": "^4.3.0", + "parse5": "^7.0.0", + "parse5-sax-parser": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, "node_modules/parse5-sax-parser": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-6.0.1.tgz", - "integrity": "sha512-kXX+5S81lgESA0LsDuGjAlBybImAChYRMT+/uKCEXFBFOeEhS52qUCydGhU3qLRD8D9DVjaUo821WK7DM4iCeg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz", + "integrity": "sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==", "dev": true, "dependencies": { - "parse5": "^6.0.1" + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/parse5-sax-parser/node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -17981,15 +13036,11 @@ "node": ">= 0.8" } }, - "node_modules/path": { - "version": "0.12.7", - "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", - "integrity": "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==", - "dev": true, - "dependencies": { - "process": "^0.11.1", - "util": "^0.10.3" - } + "node_modules/path-data-parser": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz", + "integrity": "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==", + "optional": true }, "node_modules/path-exists": { "version": "4.0.0", @@ -18024,31 +13075,26 @@ "dev": true }, "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", "dependencies": { - "lru-cache": "^10.2.0", + "lru-cache": "^9.1.1 || ^10.0.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { - "node": ">=16 || 14 >=14.18" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" - }, - "node_modules/path-scurry/node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", "engines": { - "node": ">=16 || 14 >=14.17" + "node": "14 || >=16.14" } }, "node_modules/path-to-regexp": { @@ -18061,34 +13107,33 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, "engines": { "node": ">=8" } }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "optional": true }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true + "node_modules/perfect-scrollbar": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/perfect-scrollbar/-/perfect-scrollbar-1.5.5.tgz", + "integrity": "sha512-dzalfutyP3e/FOpdlhVryN4AJ5XDVauVWxybSkLZmakFE2sS3y3pc4JnSprw8tGmHvkaG5Edr5T7LBTZ+WWU2g==" }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, "engines": { - "node": ">=8.6" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" @@ -18113,434 +13158,310 @@ } }, "node_modules/piscina": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-3.2.0.tgz", - "integrity": "sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.5.0.tgz", + "integrity": "sha512-iBaLWI56PFP81cfBSomWTmhOo9W2/yhIOL+Tk8O1vBCpK39cM0tGxB+wgYjG31qq4ohGvysfXSdnj8h7g4rZxA==", "dev": true, - "dependencies": { - "eventemitter-asyncresource": "^1.0.0", - "hdr-histogram-js": "^2.0.1", - "hdr-histogram-percentiles-obj": "^3.0.0" - }, "optionalDependencies": { "nice-napi": "^1.0.2" } }, "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/possible-typed-array-names": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/postcss": { - "version": "8.4.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz", - "integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.1", - "source-map-js": "^1.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-attribute-case-insensitive": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.2.tgz", - "integrity": "sha512-XIidXV8fDr0kKt28vqki84fRK8VW8eTuIa4PChv2MqKuT6C9UjmSKzen6KaWhWEoYvwxFCa7n/tC1SZ3tyq4SQ==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.10" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/postcss-clamp": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.1.0.tgz", - "integrity": "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": ">=7.6.0" - }, - "peerDependencies": { - "postcss": "^8.4.6" - } - }, - "node_modules/postcss-color-functional-notation": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.4.tgz", - "integrity": "sha512-2yrTAUZUab9s6CpxkxC4rVgFEVaR6/2Pipvi6qcgvnYiVqZcbDHEoBDhrXzyb7Efh2CCfHQNtcqWcIruDTIUeg==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/postcss-color-hex-alpha": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.4.tgz", - "integrity": "sha512-nLo2DCRC9eE4w2JmuKgVA3fGL3d01kGq752pVALF68qpGLmx2Qrk91QTKkdUqqp45T1K1XV8IhQpcu1hoAQflQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", "dev": true, "dependencies": { - "postcss-value-parser": "^4.2.0" + "find-up": "^6.3.0" }, "engines": { - "node": "^12 || ^14 || >=16" + "node": ">=14.16" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.4" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-color-rebeccapurple": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.1.1.tgz", - "integrity": "sha512-pGxkuVEInwLHgkNxUc4sdg4g3py7zUeCQ9sMfwyHAT+Ezk8a4OaaVZ8lIY5+oNqA/BXXgLyXv0+5wHP68R79hg==", + "node_modules/pkg-dir/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", "dev": true, "dependencies": { - "postcss-value-parser": "^4.2.0" + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" }, "engines": { - "node": "^12 || ^14 || >=16" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-custom-media": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.2.tgz", - "integrity": "sha512-7yi25vDAoHAkbhAzX9dHx2yc6ntS4jQvejrNcC+csQJAXjj15e7VcWfMgLqBNAbOvqi5uIa9huOVwdHbf+sKqg==", + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", "dev": true, "dependencies": { - "postcss-value-parser": "^4.2.0" + "p-locate": "^6.0.0" }, "engines": { - "node": "^12 || ^14 || >=16" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.3" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-custom-properties": { - "version": "12.1.11", - "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.11.tgz", - "integrity": "sha512-0IDJYhgU8xDv1KY6+VgUwuQkVtmYzRwu+dMjnmdMafXYv86SWqfxkc7qdDvWS38vsjaEtv8e0vGOUQrAiMBLpQ==", + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", "dev": true, "dependencies": { - "postcss-value-parser": "^4.2.0" + "yocto-queue": "^1.0.0" }, "engines": { - "node": "^12 || ^14 || >=16" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-custom-selectors": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-6.0.3.tgz", - "integrity": "sha512-fgVkmyiWDwmD3JbpCmB45SvvlCD6z9CG6Ie6Iere22W5aHea6oWa7EM2bpnv2Fj3I94L3VbtvX9KqwSi5aFzSg==", + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", "dev": true, "dependencies": { - "postcss-selector-parser": "^6.0.4" + "p-limit": "^4.0.0" }, "engines": { - "node": "^12 || ^14 || >=16" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.3" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-dir-pseudo-class": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.5.tgz", - "integrity": "sha512-eqn4m70P031PF7ZQIvSgy9RSJ5uI2171O/OO/zcRNYpJbvaeKFUlar1aJ7rmgiQtbm0FSPsRewjpdS0Oew7MPA==", + "node_modules/pkg-dir/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.10" - }, "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/postcss-double-position-gradients": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.2.tgz", - "integrity": "sha512-GX+FuE/uBR6eskOK+4vkXgT6pDkexLokPaz/AbJna9s5Kzp/yl488pKPjhy0obB475ovfT1Wv8ho7U/cHNaRgQ==", - "dev": true, + "node_modules/pkg-types": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.2.1.tgz", + "integrity": "sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==", + "optional": true, "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "confbox": "^0.1.8", + "mlly": "^1.7.2", + "pathe": "^1.1.2" } }, - "node_modules/postcss-env-function": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.6.tgz", - "integrity": "sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } + "node_modules/points-on-curve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", + "integrity": "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==", + "optional": true }, - "node_modules/postcss-focus-visible": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz", - "integrity": "sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==", - "dev": true, + "node_modules/points-on-path": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/points-on-path/-/points-on-path-0.2.1.tgz", + "integrity": "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==", + "optional": true, "dependencies": { - "postcss-selector-parser": "^6.0.9" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" + "path-data-parser": "0.1.0", + "points-on-curve": "0.2.0" } }, - "node_modules/postcss-focus-within": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz", - "integrity": "sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==", + "node_modules/postcss": { + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "dependencies": { - "postcss-selector-parser": "^6.0.9" + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" }, "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-font-variant": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", - "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", - "dev": true, - "peerDependencies": { - "postcss": "^8.1.0" + "node": "^10 || ^12 || >=14" } }, - "node_modules/postcss-gap-properties": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.5.tgz", - "integrity": "sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==", + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", "dev": true, - "engines": { - "node": "^12 || ^14 || >=16" + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "engines": { + "node": ">=14.0.0" }, "peerDependencies": { - "postcss": "^8.2" + "postcss": "^8.0.0" } }, - "node_modules/postcss-image-set-function": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-4.0.7.tgz", - "integrity": "sha512-9T2r9rsvYzm5ndsBE8WgtrMlIT7VbtTfE7b3BQnudUqnBcBo7L758oc+o+pdj/dUV0l5wjwSdjeOH2DZtfv8qw==", + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", "dev": true, "dependencies": { - "postcss-value-parser": "^4.2.0" + "camelcase-css": "^2.0.1" }, "engines": { - "node": "^12 || ^14 || >=16" + "node": "^12 || ^14 || >= 16" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/csstools" + "url": "https://opencollective.com/postcss/" }, "peerDependencies": { - "postcss": "^8.2" + "postcss": "^8.4.21" } }, - "node_modules/postcss-import": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz", - "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==", + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" }, "engines": { - "node": ">=10.0.0" + "node": ">= 14" }, "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-initial": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", - "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", - "dev": true, - "peerDependencies": { - "postcss": "^8.0.0" + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } } }, - "node_modules/postcss-lab-function": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.2.1.tgz", - "integrity": "sha512-xuXll4isR03CrQsmxyz92LJB2xX9n+pZJ5jE9JgcnmsCammLyKdlzrBin+25dy6wIjfhJpKBAN80gsTlCgRk2w==", + "node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", + "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==", "dev": true, - "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" - }, "engines": { - "node": "^12 || ^14 || >=16" + "node": ">=14" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "url": "https://github.com/sponsors/antonk52" } }, "node_modules/postcss-loader": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.1.tgz", - "integrity": "sha512-VRviFEyYlLjctSM93gAZtcJJ/iSkPZ79zWbN/1fSH+NisBByEiVLqpdVDrPLVSi8DX0oJo12kL/GppTBdKVXiQ==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-8.1.1.tgz", + "integrity": "sha512-0IeqyAsG6tYiDRCYKQJLAmgQr47DX6N7sFSWvQxt6AcupX8DIdmykuk/o/tx0Lze3ErGHJEp5OSRxrelC6+NdQ==", "dev": true, "dependencies": { - "cosmiconfig": "^7.0.0", - "klona": "^2.0.5", - "semver": "^7.3.7" + "cosmiconfig": "^9.0.0", + "jiti": "^1.20.0", + "semver": "^7.5.4" }, "engines": { - "node": ">= 14.15.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { + "@rspack/core": "0.x || 1.x", "postcss": "^7.0.0 || ^8.0.1", "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } } }, - "node_modules/postcss-logical": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", - "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", + "node_modules/postcss-loader/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/postcss-loader/node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", "dev": true, + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, "engines": { - "node": "^12 || ^14 || >=16" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" }, "peerDependencies": { - "postcss": "^8.4" + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/postcss-media-minmax": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", - "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", + "node_modules/postcss-loader/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, - "engines": { - "node": ">=10.0.0" + "dependencies": { + "argparse": "^2.0.1" }, - "peerDependencies": { - "postcss": "^8.1.0" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, "node_modules/postcss-media-query-parser": { @@ -18608,199 +13529,14 @@ "postcss": "^8.1.0" } }, - "node_modules/postcss-nesting": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.2.0.tgz", - "integrity": "sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==", - "dev": true, - "dependencies": { - "@csstools/selector-specificity": "^2.0.0", - "postcss-selector-parser": "^6.0.10" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/postcss-opacity-percentage": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.3.tgz", - "integrity": "sha512-An6Ba4pHBiDtyVpSLymUUERMo2cU7s+Obz6BTrS+gxkbnSBNKSuD0AVUc+CpBMrpVPKKfoVz0WQCX+Tnst0i4A==", - "dev": true, - "funding": [ - { - "type": "kofi", - "url": "https://ko-fi.com/mrcgrtz" - }, - { - "type": "liberapay", - "url": "https://liberapay.com/mrcgrtz" - } - ], - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/postcss-overflow-shorthand": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.4.tgz", - "integrity": "sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/postcss-page-break": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", - "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", - "dev": true, - "peerDependencies": { - "postcss": "^8" - } - }, - "node_modules/postcss-place": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.5.tgz", - "integrity": "sha512-wR8igaZROA6Z4pv0d+bvVrvGY4GVHihBCBQieXFY3kuSuMyOmEnnfFzHl/tQuqHZkfkIVBEbDvYcFfHmpSet9g==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/postcss-preset-env": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.7.2.tgz", - "integrity": "sha512-1q0ih7EDsZmCb/FMDRvosna7Gsbdx8CvYO5hYT120hcp2ZAuOHpSzibujZ4JpIUcAC02PG6b+eftxqjTFh5BNA==", - "dev": true, - "dependencies": { - "@csstools/postcss-cascade-layers": "^1.0.4", - "@csstools/postcss-color-function": "^1.1.0", - "@csstools/postcss-font-format-keywords": "^1.0.0", - "@csstools/postcss-hwb-function": "^1.0.1", - "@csstools/postcss-ic-unit": "^1.0.0", - "@csstools/postcss-is-pseudo-class": "^2.0.6", - "@csstools/postcss-normalize-display-values": "^1.0.0", - "@csstools/postcss-oklab-function": "^1.1.0", - "@csstools/postcss-progressive-custom-properties": "^1.3.0", - "@csstools/postcss-stepped-value-functions": "^1.0.0", - "@csstools/postcss-trigonometric-functions": "^1.0.1", - "@csstools/postcss-unset-value": "^1.0.1", - "autoprefixer": "^10.4.7", - "browserslist": "^4.21.0", - "css-blank-pseudo": "^3.0.3", - "css-has-pseudo": "^3.0.4", - "css-prefers-color-scheme": "^6.0.3", - "cssdb": "^6.6.3", - "postcss-attribute-case-insensitive": "^5.0.1", - "postcss-clamp": "^4.1.0", - "postcss-color-functional-notation": "^4.2.3", - "postcss-color-hex-alpha": "^8.0.4", - "postcss-color-rebeccapurple": "^7.1.0", - "postcss-custom-media": "^8.0.2", - "postcss-custom-properties": "^12.1.8", - "postcss-custom-selectors": "^6.0.3", - "postcss-dir-pseudo-class": "^6.0.4", - "postcss-double-position-gradients": "^3.1.1", - "postcss-env-function": "^4.0.6", - "postcss-focus-visible": "^6.0.4", - "postcss-focus-within": "^5.0.4", - "postcss-font-variant": "^5.0.0", - "postcss-gap-properties": "^3.0.3", - "postcss-image-set-function": "^4.0.6", - "postcss-initial": "^4.0.1", - "postcss-lab-function": "^4.2.0", - "postcss-logical": "^5.0.4", - "postcss-media-minmax": "^5.0.0", - "postcss-nesting": "^10.1.9", - "postcss-opacity-percentage": "^1.1.2", - "postcss-overflow-shorthand": "^3.0.3", - "postcss-page-break": "^3.0.4", - "postcss-place": "^7.0.4", - "postcss-pseudo-class-any-link": "^7.1.5", - "postcss-replace-overflow-wrap": "^4.0.0", - "postcss-selector-not": "^6.0.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/postcss-pseudo-class-any-link": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.6.tgz", - "integrity": "sha512-9sCtZkO6f/5ML9WcTLcIyV1yz9D1rf0tWc+ulKcvV30s0iZKS/ONyETvoWsr6vnrmW+X+KmuK3gV/w5EWnT37w==", + "node_modules/postcss-nested": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", + "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", "dev": true, "dependencies": { - "postcss-selector-parser": "^6.0.10" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "postcss-selector-parser": "^6.0.11" }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/postcss-replace-overflow-wrap": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", - "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", - "dev": true, - "peerDependencies": { - "postcss": "^8.0.3" - } - }, - "node_modules/postcss-resolve-nested-selector": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz", - "integrity": "sha512-HvExULSwLqHLgUy1rl3ANIqCsvMS0WHss2UOsXhXnQaZ9VCc2oBvIpXrl00IUFT5ZDITME0o6oiXeiHr2SAIfw==", - "dev": true - }, - "node_modules/postcss-safe-parser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", - "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", - "dev": true, "engines": { "node": ">=12.0" }, @@ -18809,58 +13545,26 @@ "url": "https://opencollective.com/postcss/" }, "peerDependencies": { - "postcss": "^8.3.3" - } - }, - "node_modules/postcss-scss": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.9.tgz", - "integrity": "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss-scss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "engines": { - "node": ">=12.0" - }, - "peerDependencies": { - "postcss": "^8.4.29" + "postcss": "^8.2.14" } }, - "node_modules/postcss-selector-not": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-6.0.1.tgz", - "integrity": "sha512-1i9affjAe9xu/y9uqWH+tD4r6/hDaXJruk8xn2x1vzxC2U3J3LKO3zJW4CyxlNhA56pADJ/djpEwpH1RClI2rQ==", + "node_modules/postcss-nested/node_modules/postcss-selector-parser": { + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz", + "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==", "dev": true, "dependencies": { - "postcss-selector-parser": "^6.0.10" + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" }, "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">=4" } }, "node_modules/postcss-selector-parser": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz", - "integrity": "sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==", + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", "dev": true, "dependencies": { "cssesc": "^3.0.0", @@ -18886,128 +13590,130 @@ } }, "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pretty-format": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", - "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", - "dev": true, - "dependencies": { - "@jest/schemas": "^28.1.3", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/pretty-quick": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/pretty-quick/-/pretty-quick-3.3.1.tgz", - "integrity": "sha512-3b36UXfYQ+IXXqex6mCca89jC8u0mYLqFAN5eTQKoXO6oCQYcIVYZEB/5AlBHI7JPYygReM2Vv6Vom/Gln7fBg==", - "dev": true, - "dependencies": { - "execa": "^4.1.0", - "find-up": "^4.1.0", - "ignore": "^5.3.0", - "mri": "^1.2.0", - "picocolors": "^1.0.0", - "picomatch": "^3.0.1", - "tslib": "^2.6.2" - }, + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.0.tgz", + "integrity": "sha512-J9odKxERhCQ10OC2yb93583f6UnYutOeiV5i0zEDS7UGTdUt0u+y8erxl3lBKvwo/JHyyoEdXjwp4dke9oyZ/g==", + "dev": true, "bin": { - "pretty-quick": "dist/cli.js" + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=10.13" + "node": ">=14" }, - "peerDependencies": { - "prettier": "^2.0.0" + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/pretty-quick/node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "node_modules/prettier-plugin-organize-imports": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.2.4.tgz", + "integrity": "sha512-6m8WBhIp0dfwu0SkgfOxJqh+HpdyfqSSLfKKRZSFbDuEQXDDndb8fTpRWkUrX/uBenkex3MgnVk0J3b3Y5byog==", "dev": true, - "engines": { - "node": ">= 4" + "peerDependencies": { + "@volar/vue-language-plugin-pug": "^1.0.4", + "@volar/vue-typescript": "^1.0.4", + "prettier": ">=2.0", + "typescript": ">=2.9" + }, + "peerDependenciesMeta": { + "@volar/vue-language-plugin-pug": { + "optional": true + }, + "@volar/vue-typescript": { + "optional": true + } } }, - "node_modules/pretty-quick/node_modules/picomatch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-3.0.1.tgz", - "integrity": "sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag==", + "node_modules/prettier-plugin-tailwindcss": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.1.tgz", + "integrity": "sha512-AnbeYZu0WGj+QgKciUgdMnRxrqcxltleZPgdwfA5104BHM3siBLONN/HLW1yS2HvzSNkzpQ/JAj+LN0jcJO+0w==", "dev": true, "engines": { - "node": ">=10" + "node": ">=14.21.3" }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "peerDependencies": { + "@ianvs/prettier-plugin-sort-imports": "*", + "@prettier/plugin-pug": "*", + "@shopify/prettier-plugin-liquid": "*", + "@trivago/prettier-plugin-sort-imports": "*", + "@zackad/prettier-plugin-twig-melody": "*", + "prettier": "^3.0", + "prettier-plugin-astro": "*", + "prettier-plugin-css-order": "*", + "prettier-plugin-import-sort": "*", + "prettier-plugin-jsdoc": "*", + "prettier-plugin-marko": "*", + "prettier-plugin-organize-attributes": "*", + "prettier-plugin-organize-imports": "*", + "prettier-plugin-sort-imports": "*", + "prettier-plugin-style-order": "*", + "prettier-plugin-svelte": "*" + }, + "peerDependenciesMeta": { + "@ianvs/prettier-plugin-sort-imports": { + "optional": true + }, + "@prettier/plugin-pug": { + "optional": true + }, + "@shopify/prettier-plugin-liquid": { + "optional": true + }, + "@trivago/prettier-plugin-sort-imports": { + "optional": true + }, + "@zackad/prettier-plugin-twig-melody": { + "optional": true + }, + "prettier-plugin-astro": { + "optional": true + }, + "prettier-plugin-css-order": { + "optional": true + }, + "prettier-plugin-import-sort": { + "optional": true + }, + "prettier-plugin-jsdoc": { + "optional": true + }, + "prettier-plugin-marko": { + "optional": true + }, + "prettier-plugin-organize-attributes": { + "optional": true + }, + "prettier-plugin-organize-imports": { + "optional": true + }, + "prettier-plugin-sort-imports": { + "optional": true + }, + "prettier-plugin-style-order": { + "optional": true + }, + "prettier-plugin-svelte": { + "optional": true + } } }, "node_modules/prismjs": { "version": "1.29.0", "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "optional": true, "engines": { "node": ">=6" } }, "node_modules/proc-log": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz", - "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", + "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", "dev": true, "engines": { - "node": ">= 0.6.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/process-nextick-args": { @@ -19016,15 +13722,6 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, - "node_modules/promise": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", - "dev": true, - "dependencies": { - "asap": "~2.0.3" - } - }, "node_modules/promise-inflight": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", @@ -19044,19 +13741,6 @@ "node": ">=10" } }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -19070,11 +13754,14 @@ "node": ">= 0.10" } }, - "node_modules/proxy-from-env": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", - "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==", - "dev": true + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } }, "node_modules/prr": { "version": "1.0.1", @@ -19083,146 +13770,6 @@ "dev": true, "optional": true }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true - }, - "node_modules/pug": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.3.tgz", - "integrity": "sha512-uBi6kmc9f3SZ3PXxqcHiUZLmIXgfgWooKWXcwSGwQd2Zi5Rb0bT14+8CJjJgI8AB+nndLaNgHGrcc6bPIB665g==", - "dev": true, - "dependencies": { - "pug-code-gen": "^3.0.3", - "pug-filters": "^4.0.0", - "pug-lexer": "^5.0.1", - "pug-linker": "^4.0.0", - "pug-load": "^3.0.0", - "pug-parser": "^6.0.0", - "pug-runtime": "^3.0.1", - "pug-strip-comments": "^2.0.0" - } - }, - "node_modules/pug-attrs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz", - "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==", - "dev": true, - "dependencies": { - "constantinople": "^4.0.1", - "js-stringify": "^1.0.2", - "pug-runtime": "^3.0.0" - } - }, - "node_modules/pug-code-gen": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.3.tgz", - "integrity": "sha512-cYQg0JW0w32Ux+XTeZnBEeuWrAY7/HNE6TWnhiHGnnRYlCgyAUPoyh9KzCMa9WhcJlJ1AtQqpEYHc+vbCzA+Aw==", - "dev": true, - "dependencies": { - "constantinople": "^4.0.1", - "doctypes": "^1.1.0", - "js-stringify": "^1.0.2", - "pug-attrs": "^3.0.0", - "pug-error": "^2.1.0", - "pug-runtime": "^3.0.1", - "void-elements": "^3.1.0", - "with": "^7.0.0" - } - }, - "node_modules/pug-error": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.1.0.tgz", - "integrity": "sha512-lv7sU9e5Jk8IeUheHata6/UThZ7RK2jnaaNztxfPYUY+VxZyk/ePVaNZ/vwmH8WqGvDz3LrNYt/+gA55NDg6Pg==", - "dev": true - }, - "node_modules/pug-filters": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz", - "integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==", - "dev": true, - "dependencies": { - "constantinople": "^4.0.1", - "jstransformer": "1.0.0", - "pug-error": "^2.0.0", - "pug-walk": "^2.0.0", - "resolve": "^1.15.1" - } - }, - "node_modules/pug-lexer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz", - "integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==", - "dev": true, - "dependencies": { - "character-parser": "^2.2.0", - "is-expression": "^4.0.0", - "pug-error": "^2.0.0" - } - }, - "node_modules/pug-linker": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz", - "integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==", - "dev": true, - "dependencies": { - "pug-error": "^2.0.0", - "pug-walk": "^2.0.0" - } - }, - "node_modules/pug-load": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz", - "integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==", - "dev": true, - "dependencies": { - "object-assign": "^4.1.1", - "pug-walk": "^2.0.0" - } - }, - "node_modules/pug-parser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz", - "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==", - "dev": true, - "dependencies": { - "pug-error": "^2.0.0", - "token-stream": "1.0.0" - } - }, - "node_modules/pug-runtime": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz", - "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==", - "dev": true - }, - "node_modules/pug-strip-comments": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz", - "integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==", - "dev": true, - "dependencies": { - "pug-error": "^2.0.0" - } - }, - "node_modules/pug-walk": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz", - "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==", - "dev": true - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -19232,22 +13779,19 @@ "node": ">=6" } }, - "node_modules/pyodide": { - "version": "0.26.1", - "resolved": "https://registry.npmjs.org/pyodide/-/pyodide-0.26.1.tgz", - "integrity": "sha512-P+Gm88nwZqY7uBgjbQH8CqqU6Ei/rDn7pS1t02sNZsbyLJMyE2OVXjgNuqVT3KqYWnyGREUN0DbBUCJqk8R0ew==", + "node_modules/qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", "dev": true, - "dependencies": { - "ws": "^8.5.0" - }, "engines": { - "node": ">=18.0.0" + "node": ">=0.9" } }, "node_modules/qs": { - "version": "6.10.4", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz", - "integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "dev": true, "dependencies": { "side-channel": "^1.0.4" @@ -19259,12 +13803,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -19285,195 +13823,84 @@ } ] }, - "node_modules/quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "dev": true, - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true - }, - "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dev": true, - "dependencies": { - "pify": "^2.3.0" - } - }, - "node_modules/read-package-json": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-5.0.2.tgz", - "integrity": "sha512-BSzugrt4kQ/Z0krro8zhTwV1Kd79ue25IhNN/VtHFy1mG/6Tluyi+msc0UpwaoQzxSHa28mntAjIZY6kEgfR9Q==", - "deprecated": "This package is no longer supported. Please use @npmcli/package-json instead.", - "dev": true, - "dependencies": { - "glob": "^8.0.1", - "json-parse-even-better-errors": "^2.3.1", - "normalize-package-data": "^4.0.0", - "npm-normalize-package-bin": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/read-package-json-fast": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz", - "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", - "dev": true, - "dependencies": { - "json-parse-even-better-errors": "^2.3.0", - "npm-normalize-package-bin": "^1.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/read-package-json/node_modules/npm-normalize-package-bin": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", - "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, + "node_modules/quill": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/quill/-/quill-2.0.2.tgz", + "integrity": "sha512-QfazNrhMakEdRG57IoYFwffUIr04LWJxbS/ZkidRFXYCQt63c1gK6Z7IHUXMx/Vh25WgPBU42oBaNzQ0K1R/xw==", "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "eventemitter3": "^5.0.1", + "lodash-es": "^4.17.21", + "parchment": "^3.0.0", + "quill-delta": "^5.1.0" + }, + "engines": { + "npm": ">=8.2.3" } }, - "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, + "node_modules/quill-delta": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-5.1.0.tgz", + "integrity": "sha512-X74oCeRI4/p0ucjb5Ma8adTXd9Scumz367kkMK5V/IatcX6A0vlgLgKbzXWy5nZmCGeNJm2oQX0d2Eqj+ZIlCA==", + "dependencies": { + "fast-diff": "^1.3.0", + "lodash.clonedeep": "^4.5.0", + "lodash.isequal": "^4.5.0" + }, "engines": { - "node": ">=8" + "node": ">= 12.0.0" } }, - "node_modules/read-pkg/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true + "node_modules/quill/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" }, - "node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "safe-buffer": "^5.1.0" } }, - "node_modules/read-pkg/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "dev": true, - "bin": { - "semver": "bin/semver" + "engines": { + "node": ">= 0.6" } }, - "node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, "engines": { - "node": ">=8" + "node": ">= 0.8" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "dependencies": { + "pify": "^2.3.0" } }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -19487,6 +13914,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, "dependencies": { "picomatch": "^2.2.1" }, @@ -19494,57 +13922,23 @@ "node": ">=8.10.0" } }, - "node_modules/recursive-readdir": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", - "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", - "dev": true, - "dependencies": { - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/recursive-readdir/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/recursive-readdir/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, "engines": { - "node": "*" - } - }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "dev": true, - "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" + "node": ">=8.6" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/reflect-metadata": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", - "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==" + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "dev": true }, "node_modules/regenerate": { "version": "1.4.2", @@ -19565,9 +13959,9 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", "dev": true }, "node_modules/regenerator-transform": { @@ -19585,36 +13979,6 @@ "integrity": "sha512-TVILVSz2jY5D47F4mA4MppkBrafEaiUWJO/TcZHEIuI13AqoZMkK1WMA4Om1YkYbTx+9Ki1/tSUXbceyr9saRg==", "dev": true }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", - "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, "node_modules/regexpu-core": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", @@ -19653,19 +14017,113 @@ "jsesc": "bin/jsesc" } }, - "node_modules/remove-markdown": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/remove-markdown/-/remove-markdown-0.5.0.tgz", - "integrity": "sha512-x917M80K97K5IN1L8lUvFehsfhR8cYjGQ/yAMRI9E7JIKivtl5Emo5iD13DhMr+VojzMCiYk8V2byNPwT/oapg==", - "dev": true + "node_modules/replace-in-file": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/replace-in-file/-/replace-in-file-7.1.0.tgz", + "integrity": "sha512-1uZmJ78WtqNYCSuPC9IWbweXkGxPOtk2rKuar8diTw7naVIQZiE3Tm8ACx2PCMXDtVH6N+XxwaRY2qZ2xHPqXw==", + "dependencies": { + "chalk": "^4.1.2", + "glob": "^8.1.0", + "yargs": "^17.7.2" + }, + "bin": { + "replace-in-file": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } }, - "node_modules/request-progress": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", - "integrity": "sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==", - "dev": true, + "node_modules/replace-in-file/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/replace-in-file/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/replace-in-file/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/replace-in-file/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/replace-in-file/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/replace-in-file/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/replace-in-file/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/replace-in-file/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { - "throttleit": "^1.0.0" + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, "node_modules/require-directory": { @@ -19692,12 +14150,12 @@ "dev": true }, "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "dependencies": { - "is-core-module": "^2.9.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -19708,18 +14166,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -19768,20 +14214,10 @@ "node": ">=0.10.0" } }, - "node_modules/resolve.exports": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.1.tgz", - "integrity": "sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" @@ -19790,6 +14226,11 @@ "node": ">=8" } }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, "node_modules/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", @@ -19803,22 +14244,22 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" } }, "node_modules/rfdc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", + "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", "dev": true }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "dependencies": { "glob": "^7.1.3" @@ -19844,7 +14285,6 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -19861,27 +14301,87 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "optional": true + }, + "node_modules/rollup": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.0.tgz", + "integrity": "sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.18.0", + "@rollup/rollup-android-arm64": "4.18.0", + "@rollup/rollup-darwin-arm64": "4.18.0", + "@rollup/rollup-darwin-x64": "4.18.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.18.0", + "@rollup/rollup-linux-arm-musleabihf": "4.18.0", + "@rollup/rollup-linux-arm64-gnu": "4.18.0", + "@rollup/rollup-linux-arm64-musl": "4.18.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.18.0", + "@rollup/rollup-linux-riscv64-gnu": "4.18.0", + "@rollup/rollup-linux-s390x-gnu": "4.18.0", + "@rollup/rollup-linux-x64-gnu": "4.18.0", + "@rollup/rollup-linux-x64-musl": "4.18.0", + "@rollup/rollup-win32-arm64-msvc": "4.18.0", + "@rollup/rollup-win32-ia32-msvc": "4.18.0", + "@rollup/rollup-win32-x64-msvc": "4.18.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/roughjs": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.6.6.tgz", + "integrity": "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==", + "optional": true, + "dependencies": { + "hachure-fill": "^0.5.2", + "path-data-parser": "^0.1.0", + "points-on-curve": "^0.2.0", + "points-on-path": "^0.2.1" + } + }, + "node_modules/run-applescript": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", + "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, "engines": { - "node": "*" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/robust-predicates": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", - "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" - }, "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", + "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", "dev": true, "engines": { "node": ">=0.12.0" @@ -19913,7 +14413,8 @@ "node_modules/rw": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "optional": true }, "node_modules/rxjs": { "version": "7.8.1", @@ -19923,24 +14424,6 @@ "tslib": "^2.1.0" } }, - "node_modules/safe-array-concat": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", - "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -19960,32 +14443,21 @@ } ] }, - "node_modules/safe-regex-test": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", - "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-regex": "^1.1.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "devOptional": true + }, + "node_modules/safevalues": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/safevalues/-/safevalues-0.3.4.tgz", + "integrity": "sha512-LRneZZRXNgjzwG4bDQdOTSbze3fHm1EAKN/8bePxnlEZiBmkYEDggaHbuvHI9/hoqHbGfsEA7tWS9GhYHZBBsw==" }, "node_modules/sass": { - "version": "1.53.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.53.0.tgz", - "integrity": "sha512-zb/oMirbKhUgRQ0/GFz8TSAwRq2IlR29vOUJZOx0l8sV+CkHUfHa4u5nqrG+1VceZp7Jfj59SVW9ogdhTvJDcQ==", + "version": "1.77.2", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.2.tgz", + "integrity": "sha512-eb4GZt1C3avsX3heBNlrc7I09nyT00IUuo4eFhAbeXWU2fvA7oXI53SxODVAA+zgZCk9aunAZgO+losjR3fAwA==", "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", @@ -19996,34 +14468,33 @@ "sass": "sass.js" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" } }, "node_modules/sass-loader": { - "version": "13.0.2", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.0.2.tgz", - "integrity": "sha512-BbiqbVmbfJaWVeOOAu2o7DhYWtcNmTfvroVgFXa6k2hHheMxNAeDHLNoDy/Q5aoaVlz0LH+MbMktKwm9vN/j8Q==", + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-14.2.1.tgz", + "integrity": "sha512-G0VcnMYU18a4N7VoNDegg2OuMjYtxnqzQWARVWCIVSZwJeiL9kg8QMsuIZOplsJgTzZLF6jGxI3AClj8I9nRdQ==", "dev": true, "dependencies": { - "klona": "^2.0.4", "neo-async": "^2.6.2" }, "engines": { - "node": ">= 14.15.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "fibers": ">= 3.1.0", - "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", + "@rspack/core": "0.x || 1.x", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", "sass": "^1.3.0", "sass-embedded": "*", "webpack": "^5.0.0" }, "peerDependenciesMeta": { - "fibers": { + "@rspack/core": { "optional": true }, "node-sass": { @@ -20034,81 +14505,43 @@ }, "sass-embedded": { "optional": true + }, + "webpack": { + "optional": true } } }, "node_modules/sax": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", - "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==", "dev": true, "optional": true }, - "node_modules/saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "dev": true, - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/schema-utils": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", - "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", "dev": true, "dependencies": { - "@types/json-schema": "^7.0.5", - "ajv": "^6.12.4", - "ajv-keywords": "^3.5.2" + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" }, "engines": { - "node": ">= 8.9.0" + "node": ">= 12.13.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" } }, - "node_modules/schema-utils/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/schema-utils/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/schema-utils/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, "node_modules/select": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", - "integrity": "sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==" + "integrity": "sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==", + "optional": true }, "node_modules/select-hose": { "version": "2.0.0", @@ -20130,12 +14563,10 @@ } }, "node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, "bin": { "semver": "bin/semver.js" }, @@ -20143,22 +14574,6 @@ "node": ">=10" } }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -20210,11 +14625,14 @@ "node": ">=4" } }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "node_modules/send/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } }, "node_modules/serialize-javascript": { "version": "6.0.2", @@ -20294,15 +14712,6 @@ "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", "dev": true }, - "node_modules/serve-index/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", @@ -20318,12 +14727,6 @@ "node": ">= 0.8.0" } }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true - }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -20341,25 +14744,11 @@ "node": ">= 0.4" } }, - "node_modules/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true }, "node_modules/shallow-clone": { "version": "3.0.1", @@ -20392,22 +14781,15 @@ "node": ">=8" } }, - "node_modules/shortid": { - "version": "2.2.16", - "resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.16.tgz", - "integrity": "sha512-Ugt+GIZqvGXCIItnsL+lvFJOiN7RYqlGy7QE41O3YC1xbNSeDGIRO7xg2JJXIAj1cAGnOeC1r7/T9pgrtQbv4g==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", "dev": true, - "dependencies": { - "nanoid": "^2.1.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/shortid/node_modules/nanoid": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz", - "integrity": "sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==", - "dev": true - }, "node_modules/side-channel": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", @@ -20427,87 +14809,94 @@ } }, "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "engines": { - "node": ">=8" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/slashes": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/slashes/-/slashes-3.0.12.tgz", - "integrity": "sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==", - "dev": true - }, - "node_modules/slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "node_modules/sigstore": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.3.1.tgz", + "integrity": "sha512-8G+/XDU8wNsJOQS5ysDVO0Etg9/2uA5gR9l4ZwijjlwxBcrU6RPfwi2+jJmbP+Ap1Hlp/nVAaEO4Fj22/SL2gQ==", "dev": true, "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" + "@sigstore/bundle": "^2.3.2", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.2", + "@sigstore/sign": "^2.3.2", + "@sigstore/tuf": "^2.3.4", + "@sigstore/verify": "^1.2.1" }, "engines": { - "node": ">=8" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/slice-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socket.io": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.4.tgz", + "integrity": "sha512-DcotgfP1Zg9iP/dH9zvAQcWrE0TtbMVwXmlV4T4mqsvY+gw+LqUGPfx2AoVyRk0FLME+GQhufDMyacFmw7ksqw==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" }, "engines": { - "node": ">=7.0.0" + "node": ">=10.2.0" } }, - "node_modules/slice-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "node_modules/socket.io-adapter": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.4.tgz", + "integrity": "sha512-wDNHGXGewWAjQPt3pyeYBtpWSq9cLE5UW1ZUPL/2eGK9jtse/FpXib7epSTsz0Q0m+6sg6Y4KtcFTlah1bdOVg==", + "dev": true, + "dependencies": { + "debug": "~4.3.4", + "ws": "~8.11.0" + } }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", "dev": true, + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" + "node": ">=10.0.0" } }, "node_modules/sockjs": { @@ -20536,17 +14925,36 @@ } }, "node_modules/socks-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", - "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz", + "integrity": "sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==", "dev": true, "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" + "agent-base": "^7.1.1", + "debug": "^4.3.4", + "socks": "^2.7.1" }, "engines": { - "node": ">= 10" + "node": ">= 14" + } + }, + "node_modules/sonic-forest": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sonic-forest/-/sonic-forest-1.0.3.tgz", + "integrity": "sha512-dtwajos6IWMEWXdEbW1IkEkyL2gztCAgDplRIX+OT5aRKnEd5e7r7YCxRgXZdhRP1FBdOBf8axeTPhzDv8T4wQ==", + "dev": true, + "dependencies": { + "tree-dump": "^1.0.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, "node_modules/source-map": { @@ -20568,17 +14976,16 @@ } }, "node_modules/source-map-loader": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-4.0.0.tgz", - "integrity": "sha512-i3KVgM3+QPAHNbGavK+VBq03YoJl24m9JWNbLgsjTj8aJzXG9M61bantBTNBt7CNwY2FYf+RJRYJ3pzalKjIrw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-5.0.0.tgz", + "integrity": "sha512-k2Dur7CbSLcAH73sBcIkV5xjPV4SzqO1NJ7+XaQl8if3VODDUj3FNchNGpqgJSKbvUfJuhVdv8K2Eu8/TNl2eA==", "dev": true, "dependencies": { - "abab": "^2.0.6", "iconv-lite": "^0.6.3", "source-map-js": "^1.0.2" }, "engines": { - "node": ">= 14.15.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", @@ -20588,15 +14995,16 @@ "webpack": "^5.72.1" } }, - "node_modules/source-map-resolve": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz", - "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", - "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", + "node_modules/source-map-loader/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, "dependencies": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0" + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, "node_modules/source-map-support": { @@ -20618,12 +15026,6 @@ "node": ">=0.10.0" } }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "deprecated": "Please use @jridgewell/sourcemap-codec instead" - }, "node_modules/spdx-correct": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", @@ -20634,16 +15036,6 @@ "spdx-license-ids": "^3.0.0" } }, - "node_modules/spdx-correct/node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, "node_modules/spdx-exceptions": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", @@ -20651,9 +15043,9 @@ "dev": true }, "node_modules/spdx-expression-parse": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", - "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, "dependencies": { "spdx-exceptions": "^2.1.0", @@ -20661,9 +15053,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.18", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz", - "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==", + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", + "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", "dev": true }, "node_modules/spdy": { @@ -20702,109 +15094,81 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, - "node_modules/sshpk": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", - "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", + "node_modules/ssri": { + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", + "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", "dev": true, "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" + "minipass": "^7.0.3" }, "engines": { - "node": ">=0.10.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/sshpk/node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true - }, - "node_modules/ssri": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", - "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true, - "dependencies": { - "minipass": "^3.1.1" - }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">= 0.6" } }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "node_modules/streamroller": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", + "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", "dev": true, "dependencies": { - "escape-string-regexp": "^2.0.0" + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" }, "engines": { - "node": ">=10" + "node": ">=8.0" } }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "node_modules/streamroller/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, "engines": { - "node": ">=8" + "node": ">=6 <7 || >=8" } }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "engines": { - "node": ">= 0.8" + "node_modules/streamroller/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, - "node_modules/streamsearch": { + "node_modules/streamroller/node_modules/universalify": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", - "integrity": "sha512-jos8u++JKm0ARcSUTAZXOVC0mSox7Bhn6sBgty73P1f3JGf7yG2clTbBNHUdde/kdvP2FESam+vM6l8jBrNxHA==", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true, "engines": { - "node": ">=0.8.0" + "node": ">= 4.0.0" } }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, "dependencies": { "safe-buffer": "~5.2.0" } }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -20832,55 +15196,6 @@ "node": ">=8" } }, - "node_modules/string.prototype.trim": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", - "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.0", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", - "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -20904,15 +15219,6 @@ "node": ">=8" } }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", @@ -20922,18 +15228,6 @@ "node": ">=6" } }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -20946,324 +15240,140 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/strong-log-transformer": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz", - "integrity": "sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==", - "dev": true, - "dependencies": { - "duplexer": "^0.1.1", - "minimist": "^1.2.0", - "through": "^2.3.4" - }, - "bin": { - "sl-log-transformer": "bin/sl-log-transformer.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/style-search": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz", - "integrity": "sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==", - "dev": true + "node_modules/stylis": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.4.tgz", + "integrity": "sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==", + "optional": true }, - "node_modules/stylelint": { - "version": "14.11.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.11.0.tgz", - "integrity": "sha512-OTLjLPxpvGtojEfpESWM8Ir64Z01E89xsisaBMUP/ngOx1+4VG2DPRcUyCCiin9Rd3kPXPsh/uwHd9eqnvhsYA==", + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", "dev": true, "dependencies": { - "@csstools/selector-specificity": "^2.0.2", - "balanced-match": "^2.0.0", - "colord": "^2.9.3", - "cosmiconfig": "^7.0.1", - "css-functions-list": "^3.1.0", - "debug": "^4.3.4", - "fast-glob": "^3.2.11", - "fastest-levenshtein": "^1.0.16", - "file-entry-cache": "^6.0.1", - "global-modules": "^2.0.0", - "globby": "^11.1.0", - "globjoin": "^0.1.4", - "html-tags": "^3.2.0", - "ignore": "^5.2.0", - "import-lazy": "^4.0.0", - "imurmurhash": "^0.1.4", - "is-plain-object": "^5.0.0", - "known-css-properties": "^0.25.0", - "mathml-tag-names": "^2.1.3", - "meow": "^9.0.0", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.16", - "postcss-media-query-parser": "^0.2.3", - "postcss-resolve-nested-selector": "^0.1.1", - "postcss-safe-parser": "^6.0.0", - "postcss-selector-parser": "^6.0.10", - "postcss-value-parser": "^4.2.0", - "resolve-from": "^5.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "style-search": "^0.1.0", - "supports-hyperlinks": "^2.2.0", - "svg-tags": "^1.0.0", - "table": "^6.8.0", - "v8-compile-cache": "^2.3.0", - "write-file-atomic": "^4.0.2" - }, - "bin": { - "stylelint": "bin/stylelint.js" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/stylelint" - } - }, - "node_modules/stylelint-config-prettier": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/stylelint-config-prettier/-/stylelint-config-prettier-9.0.5.tgz", - "integrity": "sha512-U44lELgLZhbAD/xy/vncZ2Pq8sh2TnpiPvo38Ifg9+zeioR+LAkHu0i6YORIOxFafZoVg0xqQwex6e6F25S5XA==", - "dev": true, "bin": { - "stylelint-config-prettier": "bin/check.js", - "stylelint-config-prettier-check": "bin/check.js" + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" }, "engines": { - "node": ">= 12" - }, - "peerDependencies": { - "stylelint": ">= 11.x < 15" - } - }, - "node_modules/stylelint-config-recommended": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-8.0.0.tgz", - "integrity": "sha512-IK6dWvE000+xBv9jbnHOnBq01gt6HGVB2ZTsot+QsMpe82doDQ9hvplxfv4YnpEuUwVGGd9y6nbaAnhrjcxhZQ==", - "dev": true, - "peerDependencies": { - "stylelint": "^14.8.0" - } - }, - "node_modules/stylelint-config-recommended-scss": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-7.0.0.tgz", - "integrity": "sha512-rGz1J4rMAyJkvoJW4hZasuQBB7y9KIrShb20l9DVEKKZSEi1HAy0vuNlR8HyCKy/jveb/BdaQFcoiYnmx4HoiA==", - "dev": true, - "dependencies": { - "postcss-scss": "^4.0.2", - "stylelint-config-recommended": "^8.0.0", - "stylelint-scss": "^4.0.0" - }, - "peerDependencies": { - "stylelint": "^14.4.0" - } - }, - "node_modules/stylelint-config-standard": { - "version": "28.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-28.0.0.tgz", - "integrity": "sha512-q/StuowDdDmFCravzGHAwgS9pjX0bdOQUEBBDIkIWsQuYGgYz/xsO8CM6eepmIQ1fc5bKdDVimlJZ6MoOUcJ5Q==", - "dev": true, - "dependencies": { - "stylelint-config-recommended": "^9.0.0" - }, - "peerDependencies": { - "stylelint": "^14.11.0" - } - }, - "node_modules/stylelint-config-standard/node_modules/stylelint-config-recommended": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-9.0.0.tgz", - "integrity": "sha512-9YQSrJq4NvvRuTbzDsWX3rrFOzOlYBmZP+o513BJN/yfEmGSr0AxdvrWs0P/ilSpVV/wisamAHu5XSk8Rcf4CQ==", - "dev": true, - "peerDependencies": { - "stylelint": "^14.10.0" - } - }, - "node_modules/stylelint-scss": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-4.7.0.tgz", - "integrity": "sha512-TSUgIeS0H3jqDZnby1UO1Qv3poi1N8wUYIJY6D1tuUq2MN3lwp/rITVo0wD+1SWTmRm0tNmGO0b7nKInnqF6Hg==", - "dev": true, - "dependencies": { - "postcss-media-query-parser": "^0.2.3", - "postcss-resolve-nested-selector": "^0.1.1", - "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0" - }, - "peerDependencies": { - "stylelint": "^14.5.1 || ^15.0.0" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/stylelint/node_modules/balanced-match": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", - "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", - "dev": true - }, - "node_modules/stylis": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.2.tgz", - "integrity": "sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==" - }, - "node_modules/stylus": { - "version": "0.58.1", - "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.58.1.tgz", - "integrity": "sha512-AYiCHm5ogczdCPMfe9aeQa4NklB2gcf4D/IhzYPddJjTgPc+k4D/EVE0yfQbZD43MHP3lPy+8NZ9fcFxkrgs/w==", - "dev": true, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dependencies": { - "css": "^3.0.0", - "debug": "^4.3.2", - "glob": "^7.1.6", - "sax": "~1.2.4", - "source-map": "^0.7.3" - }, - "bin": { - "stylus": "bin/stylus" + "has-flag": "^3.0.0" }, "engines": { - "node": "*" + "node": ">=4" } }, - "node_modules/stylus-loader": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-7.0.0.tgz", - "integrity": "sha512-WTbtLrNfOfLgzTaR9Lj/BPhQroKk/LC1hfTXSUbrxmxgfUo3Y3LpmKRVA2R1XbjvTAvOfaian9vOyfv1z99E+A==", + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, - "dependencies": { - "fast-glob": "^3.2.11", - "klona": "^2.0.5", - "normalize-path": "^3.0.0" - }, "engines": { - "node": ">= 14.15.0" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "stylus": ">=0.52.4", - "webpack": "^5.0.0" - } - }, - "node_modules/stylus/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/stylus/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, + "node_modules/svg.draggable.js": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz", + "integrity": "sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw==", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "svg.js": "^2.0.1" }, "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">= 0.8.0" } }, - "node_modules/stylus/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, + "node_modules/svg.easing.js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/svg.easing.js/-/svg.easing.js-2.0.0.tgz", + "integrity": "sha512-//ctPdJMGy22YoYGV+3HEfHbm6/69LJUTAqI2/5qBvaNHZ9uUFVC82B0Pl299HzgH13rKrBgi4+XyXXyVWWthA==", "dependencies": { - "brace-expansion": "^1.1.7" + "svg.js": ">=2.3.x" }, "engines": { - "node": "*" + "node": ">= 0.8.0" } }, - "node_modules/stylus/node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/svg.filter.js": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/svg.filter.js/-/svg.filter.js-2.0.2.tgz", + "integrity": "sha512-xkGBwU+dKBzqg5PtilaTb0EYPqPfJ9Q6saVldX+5vCRy31P6TlRCP3U9NxH3HEufkKkpNgdTLBJnmhDHeTqAkw==", "dependencies": { - "has-flag": "^3.0.0" + "svg.js": "^2.2.5" }, "engines": { - "node": ">=4" + "node": ">= 0.8.0" } }, - "node_modules/supports-hyperlinks": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", - "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", - "dev": true, + "node_modules/svg.js": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/svg.js/-/svg.js-2.7.1.tgz", + "integrity": "sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA==" + }, + "node_modules/svg.pathmorphing.js": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/svg.pathmorphing.js/-/svg.pathmorphing.js-0.1.3.tgz", + "integrity": "sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww==", "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" + "svg.js": "^2.4.0" }, "engines": { - "node": ">=8" + "node": ">= 0.8.0" } }, - "node_modules/supports-hyperlinks/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, + "node_modules/svg.resize.js": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/svg.resize.js/-/svg.resize.js-1.4.3.tgz", + "integrity": "sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw==", + "dependencies": { + "svg.js": "^2.6.5", + "svg.select.js": "^2.1.2" + }, "engines": { - "node": ">=8" + "node": ">= 0.8.0" } }, - "node_modules/supports-hyperlinks/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, + "node_modules/svg.resize.js/node_modules/svg.select.js": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-2.1.2.tgz", + "integrity": "sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ==", "dependencies": { - "has-flag": "^4.0.0" + "svg.js": "^2.2.5" }, "engines": { - "node": ">=8" + "node": ">= 0.8.0" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" + "node_modules/svg.select.js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-3.0.1.tgz", + "integrity": "sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw==", + "dependencies": { + "svg.js": "^2.6.5" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/svg-tags": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", - "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", - "dev": true - }, "node_modules/symbol-observable": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", @@ -21273,92 +15383,66 @@ "node": ">=0.10" } }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "node_modules/synckit": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.0.tgz", - "integrity": "sha512-7RnqIMq572L8PeEzKeBINYEJDDxpcH8JEgLwUqBd3TkofhFRbkq4QLR0u+36avGAhCRbk2nnmjcW9SE531hPDg==", - "dev": true, - "dependencies": { - "@pkgr/core": "^0.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/table": { - "version": "6.8.2", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz", - "integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==", + "node_modules/tailwindcss": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz", + "integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==", "dev": true, "dependencies": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=14.0.0" } }, - "node_modules/table/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/tailwindcss/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "is-glob": "^4.0.3" }, "engines": { - "node": ">=7.0.0" + "node": ">=10.13.0" } }, - "node_modules/table/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/table/node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "node_modules/tailwindcss/node_modules/postcss-selector-parser": { + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz", + "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==", "dev": true, "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" + "node": ">=4" } }, "node_modules/tapable": { @@ -21387,20 +15471,28 @@ "node": ">=10" } }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", "dev": true, "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" + "minipass": "^3.0.0" }, "engines": { - "node": ">=6" + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, "node_modules/tar/node_modules/minipass": { @@ -21412,36 +15504,32 @@ "node": ">=8" } }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/tar/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, - "node_modules/terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/terser": { - "version": "5.14.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", - "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", + "version": "5.31.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.0.tgz", + "integrity": "sha512-Q1JFAoUKE5IMfI4Z/lkE/E6+SwgzO+x4tq4v1AyBLRj8VSYvRO6A/rQrPg1yud4g0En9EKI1TvFRF2tQFcoUkg==", "dev": true, "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -21511,35 +15599,6 @@ "ajv": "^6.9.1" } }, - "node_modules/terser-webpack-plugin/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/terser-webpack-plugin/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/terser-webpack-plugin/node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -21564,39 +15623,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/terser-webpack-plugin/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/terser-webpack-plugin/node_modules/terser": { - "version": "5.31.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.2.tgz", - "integrity": "sha512-LGyRZVFm/QElZHy/CPr/O4eNZOZIzsrQ92y4v9UJe/pFJjypje2yI3C2FmPtvUEnhadlSbmG2nXtdcjHOjCfxw==", - "dev": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/terser/node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -21631,7 +15657,6 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -21666,20 +15691,38 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, - "node_modules/throttleit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.1.tgz", - "integrity": "sha512-vDZpf9Chs9mAdfY046mcPt8fg5QSZr37hEH4TXYBnDF+izxgrbRGUAAaBvIk/fJm9aOFCGFd1EsNg5AZCbnQCQ==", + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", "dev": true, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "dependencies": { + "any-promise": "^1.0.0" } }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/thingies": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", + "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", + "dev": true, + "engines": { + "node": ">=10.18" + }, + "peerDependencies": { + "tslib": "^2" + } }, "node_modules/thunky": { "version": "1.1.0", @@ -21690,93 +15733,71 @@ "node_modules/tiny-emitter": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", - "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", + "optional": true + }, + "node_modules/tinyexec": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.1.tgz", + "integrity": "sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==", + "optional": true }, "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "dependencies": { - "rimraf": "^3.0.0" + "os-tmpdir": "~1.0.2" }, "engines": { - "node": ">=8.17.0" + "node": ">=0.6.0" } }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, "engines": { "node": ">=4" } }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/token-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz", - "integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==", - "dev": true - }, - "node_modules/tough-cookie": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", - "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" + "is-number": "^7.0.0" }, "engines": { - "node": ">=6" + "node": ">=8.0" } }, - "node_modules/tough-cookie/node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true, "engines": { - "node": ">= 4.0.0" + "node": ">=0.6" } }, - "node_modules/tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "node_modules/tree-dump": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.1.tgz", + "integrity": "sha512-WCkcRBVPSlHHq1dc/px9iOfqklvzCbdRwvlNfxGZsrHqf6aZttfPrd7DJTt6oR10dwUfpFFQeVTkPbBIZxX/YA==", "dev": true, - "dependencies": { - "punycode": "^2.1.1" - }, "engines": { - "node": ">=12" + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, "node_modules/tree-kill": { @@ -21788,198 +15809,52 @@ "tree-kill": "cli.js" } }, - "node_modules/trim-newlines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", - "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "dev": true, "engines": { - "node": ">=8" + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" } }, "node_modules/ts-dedent": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "optional": true, "engines": { "node": ">=6.10" } }, - "node_modules/ts-jest": { - "version": "28.0.8", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-28.0.8.tgz", - "integrity": "sha512-5FaG0lXmRPzApix8oFG8RKjAz4ehtm8yMKOTy5HX3fY6W8kmvOrmcY0hKDElW52FJov+clhUbrKAqofnj4mXTg==", - "dev": true, - "dependencies": { - "bs-logger": "0.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "^28.0.0", - "json5": "^2.2.1", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "7.x", - "yargs-parser": "^21.0.1" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/types": "^28.0.0", - "babel-jest": "^28.0.0", - "jest": "^28.0.0", - "typescript": ">=4.3" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@jest/types": { - "optional": true - }, - "babel-jest": { - "optional": true - }, - "esbuild": { - "optional": true - } - } - }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/ts-node/node_modules/acorn-walk": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", - "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", - "dev": true, - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/tsconfig-paths/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true }, "node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "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" - } - }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "node_modules/tuf-js": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.1.tgz", + "integrity": "sha512-GwIJau9XaA8nLVbUXsN3IlFi7WmQ48gBUrl3FTkkL/XLu/POhBzfmX9hd33FNMX1qAsfl6ozO1iMmW9NC8YniA==", "dev": true, "dependencies": { - "safe-buffer": "^5.0.1" + "@tufjs/models": "2.0.1", + "debug": "^4.3.4", + "make-fetch-happen": "^13.0.1" }, "engines": { - "node": "*" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -21992,19 +15867,10 @@ "node": ">= 0.8.0" } }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, "engines": { "node": ">=10" @@ -22026,118 +15892,218 @@ "node": ">= 0.6" } }, - "node_modules/typed-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", - "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "node_modules/typed-assert": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", + "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", + "dev": true + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "devOptional": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.2.0.tgz", + "integrity": "sha512-DmnqaPcML0xYwUzgNbM1XaKXpEb7BShYf2P1tkUmmcl8hyeG7Pj08Er7R9bNy6AufabywzJcOybQAtnD/c9DGw==", "dev": true, "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.13" + "@typescript-eslint/eslint-plugin": "8.2.0", + "@typescript-eslint/parser": "8.2.0", + "@typescript-eslint/utils": "8.2.0" }, "engines": { - "node": ">= 0.4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/typed-array-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", - "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.2.0.tgz", + "integrity": "sha512-OFn80B38yD6WwpoHU2Tz/fTz7CgFqInllBoC3WP+/jLbTb4gGPTy9HBSTsbDWkMdN55XlVU0mMDYAtgvlUspGw==", "dev": true, "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0" }, "engines": { - "node": ">= 0.4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", - "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.2.0.tgz", + "integrity": "sha512-6a9QSK396YqmiBKPkJtxsgZZZVjYQ6wQ/TlI0C65z7vInaETuC6HAHD98AGLC8DyIPqHytvNuS8bBVvNLKyqvQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.2.0.tgz", + "integrity": "sha512-kiG4EDUT4dImplOsbh47B1QnNmXSoUqOjWDvCJw/o8LgfD0yr7k2uy54D5Wm0j4t71Ge1NkynGhpWdS0dEIAUA==", "dev": true, "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": ">= 0.4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/typed-array-length": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", - "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.2.0.tgz", + "integrity": "sha512-O46eaYKDlV3TvAVDNcoDzd5N550ckSe8G4phko++OCSC1dYIb9LTc3HDGYdWqWIAT5qDUKphO6sd9RrpIJJPfg==", "dev": true, "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/typescript-estree": "8.2.0" }, "engines": { - "node": ">= 0.4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" } }, - "node_modules/typed-assert": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", - "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", - "dev": true - }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", - "dev": true - }, - "node_modules/typescript": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" + "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.2.0.tgz", + "integrity": "sha512-sbgsPMW9yLvS7IhCi8IpuK1oBmtbWUNP+hBdwl/I9nzqVsszGnNGti5r9dUtF5RLivHUFFIdRvLiTsPhzSyJ3Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.2.0", + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": ">=4.2.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "node_modules/typescript-eslint/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typescript-eslint/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ua-parser-js": { + "version": "0.7.37", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.37.tgz", + "integrity": "sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "engines": { + "node": "*" + } + }, + "node_modules/ufo": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", + "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", + "optional": true + }, + "node_modules/undici": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.18.0.tgz", + "integrity": "sha512-nT8jjv/fE9Et1ilR6QoW8ingRTY2Pp4l2RUrdzV5Yz35RJDrtPc1DXvuNqcpsJSGIRHFdt3YKKktTzJA6r0fTA==", + "dev": true, + "engines": { + "node": ">=18.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", @@ -22179,28 +16145,33 @@ } }, "node_modules/unique-filename": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", "dev": true, "dependencies": { - "unique-slug": "^2.0.0" + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/unique-slug": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", - "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", "dev": true, "dependencies": { "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, "engines": { "node": ">= 10.0.0" } @@ -22214,19 +16185,11 @@ "node": ">= 0.8" } }, - "node_modules/untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/update-browserslist-db": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", - "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, "funding": [ { "type": "opencollective", @@ -22242,8 +16205,8 @@ } ], "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" + "escalade": "^3.1.1", + "picocolors": "^1.0.0" }, "bin": { "update-browserslist-db": "cli.js" @@ -22252,191 +16215,585 @@ "browserslist": ">= 4.21.0" } }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz", + "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vite": { + "version": "5.2.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.11.tgz", + "integrity": "sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==", + "dev": true, + "dependencies": { + "esbuild": "^0.20.1", + "postcss": "^8.4.38", + "rollup": "^4.13.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "cpu": [ + "mips64el" + ], "dev": true, - "dependencies": { - "punycode": "^2.1.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "cpu": [ + "ppc64" + ], "dev": true, - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/util": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", - "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "cpu": [ + "riscv64" + ], "dev": true, - "dependencies": { - "inherits": "2.0.3" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/util/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "cpu": [ + "s390x" + ], "dev": true, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4.0" + "node": ">=12" } }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "cpu": [ + "x64" + ], "dev": true, - "bin": { - "uuid": "dist/bin/uuid" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "node_modules/v8-to-istanbul": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", - "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^2.0.0" - }, + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">=10.12.0" + "node": ">=12" } }, - "node_modules/v8-to-istanbul/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" } }, - "node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" } }, - "node_modules/validate-npm-package-name": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-4.0.0.tgz", - "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "builtins": "^5.0.0" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=12" } }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "cpu": [ + "ia32" + ], "dev": true, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">= 0.8" + "node": ">=12" } }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "cpu": [ + "x64" + ], "dev": true, - "engines": [ - "node >=0.6.0" + "optional": true, + "os": [ + "win32" ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" } }, "node_modules/void-elements": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", - "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "deprecated": "Use your platform's native performance.now() and performance.timeOrigin.", - "dev": true, - "dependencies": { - "browser-process-hrtime": "^1.0.0" + "node_modules/vscode-jsonrpc": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "optional": true, + "engines": { + "node": ">=14.0.0" } }, - "node_modules/w3c-xmlserializer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-3.0.0.tgz", - "integrity": "sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg==", - "dev": true, + "node_modules/vscode-languageserver": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", + "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", + "optional": true, "dependencies": { - "xml-name-validator": "^4.0.0" + "vscode-languageserver-protocol": "3.17.5" }, - "engines": { - "node": ">=12" + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" } }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, + "node_modules/vscode-languageserver-protocol": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "optional": true, "dependencies": { - "makeerror": "1.0.12" + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" } }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "optional": true + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "optional": true + }, + "node_modules/vscode-uri": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", + "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", + "optional": true + }, "node_modules/watchpack": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", @@ -22463,54 +16820,45 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "dev": true, "dependencies": { "defaults": "^1.0.3" } }, - "node_modules/web-worker": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.3.0.tgz", - "integrity": "sha512-BSR9wyRsy/KOValMgd5kMyr3JzpdeoR9KVId8u5GVlTTAtNChlsE4yTxeY7zMdNSyOmoKBv8NH2qeRY9Tg+IaA==" - }, - "node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true, - "engines": { - "node": ">=12" - } + "node_modules/weak-lru-cache": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", + "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==", + "dev": true }, "node_modules/webpack": { - "version": "5.73.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.73.0.tgz", - "integrity": "sha512-svjudQRPPa0YiOYa2lM/Gacw0r6PvxptHj4FuEKQ2kX05ZLkjbVc5MnPs6its5j7IZljnIqSVo/OsY2X0IpHGA==", + "version": "5.91.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.91.0.tgz", + "integrity": "sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.9.3", - "es-module-lexer": "^0.9.0", + "enhanced-resolve": "^5.16.0", + "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", + "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", + "schema-utils": "^3.2.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.3.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", "webpack-sources": "^3.2.3" }, "bin": { @@ -22529,156 +16877,225 @@ } } }, - "node_modules/webpack-dev-middleware": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", - "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", - "dev": true, - "dependencies": { - "colorette": "^2.0.10", - "memfs": "^3.4.3", - "mime-types": "^2.1.31", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" - } - }, - "node_modules/webpack-dev-middleware/node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true - }, - "node_modules/webpack-dev-middleware/node_modules/schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" + "node_modules/webpack-dev-middleware": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.2.1.tgz", + "integrity": "sha512-hRLz+jPQXo999Nx9fXVdKlg/aehsw1ajA9skAneGmT03xwmyuhvF93p6HUKKbWhXdcERtGTzUCtIQr+2IQegrA==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^4.6.0", + "mime-types": "^2.1.31", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } } }, "node_modules/webpack-dev-server": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.9.3.tgz", - "integrity": "sha512-3qp/eoboZG5/6QgiZ3llN8TUzkSpYg1Ko9khWX1h40MIEUNS2mDoIa8aXsPfskER+GbTvs/IJZ1QTBBhhuetSw==", - "dev": true, - "dependencies": { - "@types/bonjour": "^3.5.9", - "@types/connect-history-api-fallback": "^1.3.5", - "@types/express": "^4.17.13", - "@types/serve-index": "^1.9.1", - "@types/serve-static": "^1.13.10", - "@types/sockjs": "^0.3.33", - "@types/ws": "^8.5.1", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.0.4.tgz", + "integrity": "sha512-dljXhUgx3HqKP2d8J/fUMvhxGhzjeNVarDLcbO/EWMSgRizDkxHQDZQaLFL5VJY9tRBj2Gz+rvCEYYvhbqPHNA==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.13", + "@types/connect-history-api-fallback": "^1.5.4", + "@types/express": "^4.17.21", + "@types/serve-index": "^1.9.4", + "@types/serve-static": "^1.15.5", + "@types/sockjs": "^0.3.36", + "@types/ws": "^8.5.10", "ansi-html-community": "^0.0.8", - "bonjour-service": "^1.0.11", - "chokidar": "^3.5.3", + "bonjour-service": "^1.2.1", + "chokidar": "^3.6.0", "colorette": "^2.0.10", "compression": "^1.7.4", "connect-history-api-fallback": "^2.0.0", "default-gateway": "^6.0.3", "express": "^4.17.3", "graceful-fs": "^4.2.6", - "html-entities": "^2.3.2", + "html-entities": "^2.4.0", "http-proxy-middleware": "^2.0.3", - "ipaddr.js": "^2.0.1", - "open": "^8.0.9", - "p-retry": "^4.5.0", - "rimraf": "^3.0.2", - "schema-utils": "^4.0.0", - "selfsigned": "^2.0.1", + "ipaddr.js": "^2.1.0", + "launch-editor": "^2.6.1", + "open": "^10.0.3", + "p-retry": "^6.2.0", + "rimraf": "^5.0.5", + "schema-utils": "^4.2.0", + "selfsigned": "^2.4.1", "serve-index": "^1.9.1", "sockjs": "^0.3.24", "spdy": "^4.0.2", - "webpack-dev-middleware": "^5.3.1", - "ws": "^8.4.2" + "webpack-dev-middleware": "^7.1.0", + "ws": "^8.16.0" }, "bin": { "webpack-dev-server": "bin/webpack-dev-server.js" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^4.37.0 || ^5.0.0" + "webpack": "^5.0.0" }, "peerDependenciesMeta": { + "webpack": { + "optional": true + }, "webpack-cli": { "optional": true } } }, - "node_modules/webpack-dev-server/node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true + "node_modules/webpack-dev-server/node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/webpack-dev-server/node_modules/ipaddr.js": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", - "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "node_modules/webpack-dev-server/node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", "dev": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, "engines": { - "node": ">= 10" + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } } }, - "node_modules/webpack-dev-server/node_modules/schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "node_modules/webpack-dev-server/node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", "dev": true, "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" + "is-inside-container": "^1.0.0" }, "engines": { - "node": ">= 12.13.0" + "node": ">=16" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/webpack-dev-server/node_modules/open": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", + "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", + "dev": true, + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/webpack-dev-server/node_modules/rimraf": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", + "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", + "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, "node_modules/webpack-merge": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", - "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", "dev": true, "dependencies": { "clone-deep": "^4.0.1", + "flat": "^5.0.2", "wildcard": "^2.0.0" }, "engines": { "node": ">=10.0.0" } }, + "node_modules/webpack-merge/node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, "node_modules/webpack-sources": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", @@ -22734,10 +17151,10 @@ "ajv": "^6.9.1" } }, - "node_modules/webpack/node_modules/es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "node_modules/webpack/node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, "node_modules/webpack/node_modules/json-schema-traverse": { @@ -22787,40 +17204,6 @@ "node": ">=0.8.0" } }, - "node_modules/whatwg-encoding": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", - "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", - "dev": true, - "dependencies": { - "iconv-lite": "0.6.3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-mimetype": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", - "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-url": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-10.0.0.tgz", - "integrity": "sha512-CLxxCmdUby142H5FZzn4D8ikO1cmypvXVQktsgosNy4a4BHrDHeciBBGZhb0bNoR5/MltoCatso+vFjjGx8t0w==", - "dev": true, - "dependencies": { - "tr46": "^3.0.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -22835,83 +17218,12 @@ "node": ">= 8" } }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "node_modules/widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "dev": true, - "dependencies": { - "string-width": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/wildcard": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", "dev": true }, - "node_modules/with": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz", - "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.9.6", - "@babel/types": "^7.9.6", - "assert-never": "^1.2.1", - "babel-walk": "3.0.0-canary-5" - }, - "engines": { - "node": ">= 10.0.0" - } - }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -22922,19 +17234,17 @@ } }, "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": ">=8" } }, "node_modules/wrap-ansi-cjs": { @@ -22988,6 +17298,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -23002,6 +17313,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -23012,37 +17324,25 @@ "node_modules/wrap-ansi/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, - "node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", "dev": true, "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" + "utf-8-validate": "^5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -23053,36 +17353,6 @@ } } }, - "node_modules/xml-name-validator": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", - "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "node_modules/xregexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.0.0.tgz", - "integrity": "sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg==", - "dev": true - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, - "engines": { - "node": ">=0.4" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -23094,80 +17364,62 @@ "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true }, "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", + "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==", "dev": true, + "bin": { + "yaml": "bin.mjs" + }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dependencies": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" + "yargs-parser": "^21.1.1" }, "engines": { "node": ">=12" } }, "node_modules/yargs-parser": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", - "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "engines": { "node": ">=12" } }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dev": true, - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12.20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/zone.js": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.11.8.tgz", - "integrity": "sha512-82bctBg2hKcEJ21humWIkXRlLBBmrc3nN7DFh5LGGhcyycO2S7FN8NmdvlcKaGFDNVL4/9kFLmwmInTavdJERA==", - "dependencies": { - "tslib": "^2.3.0" - } + "version": "0.14.6", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.14.6.tgz", + "integrity": "sha512-vyRNFqofdaHVdWAy7v3Bzmn84a1JHWSjpuTZROT/uYn8I3p2cmo7Ro9twFmYRQDPhiYOV7QLk0hhY4JJQVqS6Q==" } } } diff --git a/frontend/package.json b/frontend/package.json index ea9f7558..8a049cbc 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,105 +1,77 @@ { - "name": "sophia-ng", - "version": "1.0.0", + "name": "@sophia/ui", + "version": "20.0.0", + "description": "Sophia AI platform", + "author": "https://themeforest.net/user/srcn, Daniel Campagnoli, TrafficGuard Pty Ltd, and contributors", + "license": "https://themeforest.net/licenses/standard", "private": true, "scripts": { "ng": "ng", - "build": "npm run write:env -s && ng build --base-href=/ui/", - "start": "npm run write:env -s && ng serve --host 0.0.0.0 --proxy-config proxy.conf.js", + "start": "npm run write:env -s && ng serve --host 0.0.0.0", "start:local": "dotenv -e ../variables/local.env -- npm run start", - "deploy": "npm run write:env -s && ng deploy", - "lint": "ng lint --fix=true && npm run prettier", - "lint:ci": "ng lint && npm run prettier:check", - "stylelint": "stylelint \"src/**/*.scss\"", - "test": "npm run write:env -s && ng test", - "test:ci": "npm run write:env -s && npm run lint:ci -s && ng run sophia-ng:test:ci", - "e2e": "npm run write:env -s && ng e2e", - "cypress:open": "npm run write:env -s && ng run sophia-ng:cypress-open", - "cypress:run": "npm run write:env -s && ng run sophia-ng:cypress-run", - "translations:extract": "ngx-translate-extract --input ./src --output ./src/translations/template.json --format=json --clean --sort", - "docs": "hads ./docs -o", - "write:env": "ngx-scripts env npm_package_version SERVER_URL GCLOUD_PROJECT FIRESTORE_DATABASE AUTH", - "prettier": "prettier --write \"./src/**/*.{ts,js,html,scss}\"", - "prettier:check": "prettier --list-different \"./src/**/*.{ts,js,html,scss}\"", - "postinstall": "npm run prettier -s", - "generate": "ng generate" + "build": "npm run write:env -s && ng build --base-href=/ui/", + "watch": "ng build --watch --configuration development", + "test": "ng test", + "lint": "ng lint", + "lint:ci": "echo skipping", + "write:env": "ngx-scripts env npm_package_version SERVER_URL GCLOUD_PROJECT FIRESTORE_DATABASE AUTH" }, "dependencies": { - "@angular/animations": "~14.1.3", - "@angular/cdk": "~14.1.3", - "@angular/common": "~14.1.3", - "@angular/compiler": "~14.1.3", - "@angular/core": "~14.1.3", - "@angular/flex-layout": "^14.0.0-beta.40", - "@angular/forms": "~14.1.3", - "@angular/localize": "~14.1.3", - "@angular/material": "~14.1.3", - "@angular/platform-browser": "~14.1.3", - "@angular/platform-browser-dynamic": "~14.1.3", - "@angular/router": "~14.1.3", - "@fastify/static": "^7.0.4", - "@ngx-translate/core": "^14.0.0", - "date-fns": "^2.29.2", - "lodash": "^4.17.20", - "marked": "^12.0.2", - "material-design-icons-iconfont": "^6.1.0", - "ngx-markdown": "^14.0.1", - "rxjs": "^7.5.0", - "tslib": "^2.3.0", - "zone.js": "~0.11.4" + "@angular/animations": "18.0.1", + "@angular/cdk": "18.0.1", + "@angular/common": "18.0.1", + "@angular/compiler": "18.0.1", + "@angular/core": "18.0.1", + "@angular/forms": "18.0.1", + "@angular/material": "18.0.1", + "@angular/material-luxon-adapter": "18.0.1", + "@angular/platform-browser": "18.0.1", + "@angular/platform-browser-dynamic": "18.0.1", + "@angular/router": "18.0.1", + "@ngneat/transloco": "6.0.4", + "apexcharts": "3.54.1", + "crypto-js": "4.2.0", + "highlight.js": "11.9.0", + "lodash-es": "4.17.21", + "luxon": "3.4.4", + "ng-apexcharts": "1.11.0", + "ngx-markdown": "^18.1.0", + "ngx-quill": "26.0.1", + "perfect-scrollbar": "1.5.5", + "quill": "2.0.2", + "rxjs": "7.8.1", + "tslib": "2.6.2", + "zone.js": "0.14.6" }, "devDependencies": { - "@angular-builders/jest": "^14.0.1", - "@angular-devkit/build-angular": "~14.1.3", - "@angular-eslint/builder": "~14.0.3", - "@angular-eslint/eslint-plugin": "~14.0.3", - "@angular-eslint/eslint-plugin-template": "~14.0.3", - "@angular-eslint/schematics": "~14.0.3", - "@angular-eslint/template-parser": "~14.0.3", - "@angular/cli": "~14.1.3", - "@angular/compiler-cli": "~14.1.3", - "@angular/language-service": "~14.1.3", - "@biesbjerg/ngx-translate-extract": "^7.0.3", - "@biesbjerg/ngx-translate-extract-marker": "^1.0.0", - "@cypress/schematic": "^2.0.3", - "@ngneat/until-destroy": "^9.0.0", - "@ngx-rocket/scripts": "^5.2.2", - "@types/jest": "^28.1.8", - "@types/lodash": "^4.14.184", - "@types/node": "^14.18.26", - "@typescript-eslint/eslint-plugin": "~5.34.0", - "@typescript-eslint/parser": "~5.34.0", - "cypress": "~10.6.0", - "dotenv-cli": "^7.4.2", - "eslint": "^8.3.0", - "eslint-plugin-import": "2.29.1", - "eslint-plugin-jsdoc": "48.7.0", - "eslint-plugin-prefer-arrow": "1.2.3", - "hads": "^3.0.0", - "https-proxy-agent": "^5.0.0", - "husky": "^8.0.1", - "jest": "^28.1.3", - "postcss": "^8.4.5", - "prettier": "^2.2.1", - "pretty-quick": "^3.1.0", - "pyodide": "^0.26.1", - "stylelint": "~14.11.0", - "stylelint-config-prettier": "^9.0.3", - "stylelint-config-recommended-scss": "~7.0.0", - "stylelint-config-standard": "~28.0.0", - "ts-jest": "^28.0.8", - "ts-node": "^10.1.0", - "typescript": "~4.7.4" - }, - "prettier": { - "singleQuote": true, - "overrides": [ - { - "files": "*.scss", - "options": { - "singleQuote": false - } - } - ] + "@angular-devkit/build-angular": "18.0.2", + "@angular/cli": "18.0.2", + "@angular/compiler-cli": "18.0.1", + "@tailwindcss/typography": "0.5.13", + "@types/chroma-js": "2.4.4", + "@types/crypto-js": "4.2.2", + "@types/highlight.js": "10.1.0", + "@types/jasmine": "5.1.4", + "@types/lodash": "4.17.4", + "@types/lodash-es": "4.17.12", + "@types/luxon": "3.4.2", + "angular-eslint": "18.3.1", + "autoprefixer": "10.4.19", + "chroma-js": "2.4.2", + "eslint": "^9.9.1", + "jasmine-core": "5.1.2", + "karma": "6.4.3", + "karma-chrome-launcher": "3.2.0", + "karma-coverage": "2.2.1", + "karma-jasmine": "5.1.0", + "karma-jasmine-html-reporter": "2.1.0", + "lodash": "4.17.21", + "postcss": "8.4.38", + "prettier": "3.3.0", + "prettier-plugin-organize-imports": "3.2.4", + "prettier-plugin-tailwindcss": "0.6.1", + "tailwindcss": "3.4.3", + "typescript": "5.4.5", + "typescript-eslint": "8.2.0" } -} +} \ No newline at end of file diff --git a/frontend/projectInfo.json b/frontend/projectInfo.json deleted file mode 100644 index efef9b25..00000000 --- a/frontend/projectInfo.json +++ /dev/null @@ -1,12 +0,0 @@ -[ - { - "baseDir": "./", - "language": "angular", - "initialise": "npm install", - "compile": "npm run build", - "format": "npm run prettier", - "staticAnalysis": "npm run lint", - "test": "npm run test", - "languageTools": "typescript" - } -] diff --git a/frontend/proxy.conf.js b/frontend/proxy.conf.js deleted file mode 100644 index f8b84680..00000000 --- a/frontend/proxy.conf.js +++ /dev/null @@ -1,41 +0,0 @@ -const HttpsProxyAgent = require('https-proxy-agent'); - -/* - * API proxy configuration. - * This allows you to proxy HTTP request like `http.get('/api/stuff')` to another server/port. - * This is especially useful during app development to avoid CORS issues while running a local server. - * For more details and options, see https://angular.io/guide/build#using-corporate-proxy - */ -const proxyConfig = [ - { - context: '/api', - pathRewrite: { '^/api': '' }, - target: 'https://api.chucknorris.io', - changeOrigin: true, - secure: false, - }, -]; - -/* - * Configures a corporate proxy agent for the API proxy if needed. - */ -function setupForCorporateProxy(proxyConfig) { - if (!Array.isArray(proxyConfig)) { - proxyConfig = [proxyConfig]; - } - - const proxyServer = process.env.http_proxy || process.env.HTTP_PROXY; - let agent = null; - - if (proxyServer) { - console.log(`Using corporate proxy server: ${proxyServer}`); - agent = new HttpsProxyAgent(proxyServer); - proxyConfig.forEach((entry) => { - entry.agent = agent; - }); - } - - return proxyConfig; -} - -module.exports = setupForCorporateProxy(proxyConfig); diff --git a/frontend/public/fonts/inter/Inter-italic.var.woff2 b/frontend/public/fonts/inter/Inter-italic.var.woff2 new file mode 100644 index 00000000..03875311 Binary files /dev/null and b/frontend/public/fonts/inter/Inter-italic.var.woff2 differ diff --git a/frontend/public/fonts/inter/Inter-roman.var.woff2 b/frontend/public/fonts/inter/Inter-roman.var.woff2 new file mode 100644 index 00000000..a6efdc48 Binary files /dev/null and b/frontend/public/fonts/inter/Inter-roman.var.woff2 differ diff --git a/frontend/public/fonts/inter/inter.css b/frontend/public/fonts/inter/inter.css new file mode 100644 index 00000000..3294b018 --- /dev/null +++ b/frontend/public/fonts/inter/inter.css @@ -0,0 +1,17 @@ +@font-face { + font-family: 'Inter var'; + font-weight: 100 900; + font-display: swap; + font-style: normal; + font-named-instance: 'Regular'; + src: url("Inter-roman.var.woff2?v=3.18") format("woff2"); +} + +@font-face { + font-family: 'Inter var'; + font-weight: 100 900; + font-display: swap; + font-style: italic; + font-named-instance: 'Italic'; + src: url("Inter-italic.var.woff2?v=3.18") format("woff2"); +} diff --git a/frontend/public/i18n/en.json b/frontend/public/i18n/en.json new file mode 100644 index 00000000..66a901c5 --- /dev/null +++ b/frontend/public/i18n/en.json @@ -0,0 +1,5 @@ +{ + "welcome-back": "Welcome back", + "Project": "Project", + "Analytics": "Analytics" +} diff --git a/frontend/public/icons/feather.svg b/frontend/public/icons/feather.svg new file mode 100644 index 00000000..e74e1624 --- /dev/null +++ b/frontend/public/icons/feather.svg @@ -0,0 +1,4309 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/public/icons/heroicons-mini.svg b/frontend/public/icons/heroicons-mini.svg new file mode 100644 index 00000000..d860c88c --- /dev/null +++ b/frontend/public/icons/heroicons-mini.svg @@ -0,0 +1,940 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/public/icons/heroicons-outline.svg b/frontend/public/icons/heroicons-outline.svg new file mode 100644 index 00000000..7f337e32 --- /dev/null +++ b/frontend/public/icons/heroicons-outline.svg @@ -0,0 +1,893 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/public/icons/heroicons-solid.svg b/frontend/public/icons/heroicons-solid.svg new file mode 100644 index 00000000..c669d9b7 --- /dev/null +++ b/frontend/public/icons/heroicons-solid.svg @@ -0,0 +1,958 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/public/icons/material-outline.svg b/frontend/public/icons/material-outline.svg new file mode 100644 index 00000000..d378c927 --- /dev/null +++ b/frontend/public/icons/material-outline.svg @@ -0,0 +1,3586 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/public/icons/material-solid.svg b/frontend/public/icons/material-solid.svg new file mode 100644 index 00000000..b8c8fe3e --- /dev/null +++ b/frontend/public/icons/material-solid.svg @@ -0,0 +1,3586 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Asset 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +ic_edit_off_24px + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +ic_recommend_24px + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +ic_dialer_rtt_revised_24px + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/public/icons/material-twotone.svg b/frontend/public/icons/material-twotone.svg new file mode 100644 index 00000000..70f18142 --- /dev/null +++ b/frontend/public/icons/material-twotone.svg @@ -0,0 +1,3586 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/public/images/logo/s.png b/frontend/public/images/logo/s.png new file mode 100644 index 00000000..3cb31663 Binary files /dev/null and b/frontend/public/images/logo/s.png differ diff --git a/frontend/public/styles/splash-screen.css b/frontend/public/styles/splash-screen.css new file mode 100644 index 00000000..fc75aeac --- /dev/null +++ b/frontend/public/styles/splash-screen.css @@ -0,0 +1,80 @@ +body fuse-splash-screen { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #111827; + color: #F9FAFB; + z-index: 999999; + pointer-events: none; + opacity: 1; + visibility: visible; + transition: opacity 400ms cubic-bezier(0.4, 0, 0.2, 1); +} + +body fuse-splash-screen img { + width: 120px; + max-width: 120px; +} + +body fuse-splash-screen .spinner { + display: flex; + align-items: center; + justify-content: space-between; + margin-top: 40px; + width: 56px; +} + +body fuse-splash-screen .spinner > div { + width: 12px; + height: 12px; + background-color: #1E96F7; + border-radius: 100%; + display: inline-block; + -webkit-animation: fuse-bouncedelay 1s infinite ease-in-out both; + animation: fuse-bouncedelay 1s infinite ease-in-out both; +} + +body fuse-splash-screen .spinner .bounce1 { + -webkit-animation-delay: -0.32s; + animation-delay: -0.32s; +} + +body fuse-splash-screen .spinner .bounce2 { + -webkit-animation-delay: -0.16s; + animation-delay: -0.16s; +} + +@-webkit-keyframes fuse-bouncedelay { + 0%, 80%, 100% { + -webkit-transform: scale(0) + } + 40% { + -webkit-transform: scale(1.0) + } +} + +@keyframes fuse-bouncedelay { + 0%, 80%, 100% { + -webkit-transform: scale(0); + transform: scale(0); + } + 40% { + -webkit-transform: scale(1.0); + transform: scale(1.0); + } +} + +body:not(.fuse-splash-screen-hidden) { + overflow: hidden; +} + +body.fuse-splash-screen-hidden fuse-splash-screen { + visibility: hidden; + opacity: 0; +} diff --git a/frontend/src/@fuse/animations/defaults.ts b/frontend/src/@fuse/animations/defaults.ts new file mode 100644 index 00000000..4da64f64 --- /dev/null +++ b/frontend/src/@fuse/animations/defaults.ts @@ -0,0 +1,12 @@ +export class FuseAnimationCurves { + static standard = 'cubic-bezier(0.4, 0.0, 0.2, 1)'; + static deceleration = 'cubic-bezier(0.0, 0.0, 0.2, 1)'; + static acceleration = 'cubic-bezier(0.4, 0.0, 1, 1)'; + static sharp = 'cubic-bezier(0.4, 0.0, 0.6, 1)'; +} + +export class FuseAnimationDurations { + static complex = '375ms'; + static entering = '225ms'; + static exiting = '195ms'; +} diff --git a/frontend/src/@fuse/animations/expand-collapse.ts b/frontend/src/@fuse/animations/expand-collapse.ts new file mode 100644 index 00000000..c02c0e74 --- /dev/null +++ b/frontend/src/@fuse/animations/expand-collapse.ts @@ -0,0 +1,37 @@ +import { + animate, + state, + style, + transition, + trigger, +} from '@angular/animations'; +import { + FuseAnimationCurves, + FuseAnimationDurations, +} from '@fuse/animations/defaults'; + +// ----------------------------------------------------------------------------------------------------- +// @ Expand / collapse +// ----------------------------------------------------------------------------------------------------- +const expandCollapse = trigger('expandCollapse', [ + state( + 'void, collapsed', + style({ + height: '0', + }) + ), + + state('*, expanded', style('*')), + + // Prevent the transition if the state is false + transition('void <=> false, collapsed <=> false, expanded <=> false', []), + + // Transition + transition('void <=> *, collapsed <=> expanded', animate('{{timings}}'), { + params: { + timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`, + }, + }), +]); + +export { expandCollapse }; diff --git a/frontend/src/@fuse/animations/fade.ts b/frontend/src/@fuse/animations/fade.ts new file mode 100644 index 00000000..0afbf111 --- /dev/null +++ b/frontend/src/@fuse/animations/fade.ts @@ -0,0 +1,330 @@ +import { + animate, + state, + style, + transition, + trigger, +} from '@angular/animations'; +import { + FuseAnimationCurves, + FuseAnimationDurations, +} from '@fuse/animations/defaults'; + +// ----------------------------------------------------------------------------------------------------- +// @ Fade in +// ----------------------------------------------------------------------------------------------------- +const fadeIn = trigger('fadeIn', [ + state( + 'void', + style({ + opacity: 0, + }) + ), + + state( + '*', + style({ + opacity: 1, + }) + ), + + // Prevent the transition if the state is false + transition('void => false', []), + + // Transition + transition('void => *', animate('{{timings}}'), { + params: { + timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`, + }, + }), +]); + +// ----------------------------------------------------------------------------------------------------- +// @ Fade in top +// ----------------------------------------------------------------------------------------------------- +const fadeInTop = trigger('fadeInTop', [ + state( + 'void', + style({ + opacity: 0, + transform: 'translate3d(0, -100%, 0)', + }) + ), + + state( + '*', + style({ + opacity: 1, + transform: 'translate3d(0, 0, 0)', + }) + ), + + // Prevent the transition if the state is false + transition('void => false', []), + + // Transition + transition('void => *', animate('{{timings}}'), { + params: { + timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`, + }, + }), +]); + +// ----------------------------------------------------------------------------------------------------- +// @ Fade in bottom +// ----------------------------------------------------------------------------------------------------- +const fadeInBottom = trigger('fadeInBottom', [ + state( + 'void', + style({ + opacity: 0, + transform: 'translate3d(0, 100%, 0)', + }) + ), + + state( + '*', + style({ + opacity: 1, + transform: 'translate3d(0, 0, 0)', + }) + ), + + // Prevent the transition if the state is false + transition('void => false', []), + + // Transition + transition('void => *', animate('{{timings}}'), { + params: { + timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`, + }, + }), +]); + +// ----------------------------------------------------------------------------------------------------- +// @ Fade in left +// ----------------------------------------------------------------------------------------------------- +const fadeInLeft = trigger('fadeInLeft', [ + state( + 'void', + style({ + opacity: 0, + transform: 'translate3d(-100%, 0, 0)', + }) + ), + + state( + '*', + style({ + opacity: 1, + transform: 'translate3d(0, 0, 0)', + }) + ), + + // Prevent the transition if the state is false + transition('void => false', []), + + // Transition + transition('void => *', animate('{{timings}}'), { + params: { + timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`, + }, + }), +]); + +// ----------------------------------------------------------------------------------------------------- +// @ Fade in right +// ----------------------------------------------------------------------------------------------------- +const fadeInRight = trigger('fadeInRight', [ + state( + 'void', + style({ + opacity: 0, + transform: 'translate3d(100%, 0, 0)', + }) + ), + + state( + '*', + style({ + opacity: 1, + transform: 'translate3d(0, 0, 0)', + }) + ), + + // Prevent the transition if the state is false + transition('void => false', []), + + // Transition + transition('void => *', animate('{{timings}}'), { + params: { + timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`, + }, + }), +]); + +// ----------------------------------------------------------------------------------------------------- +// @ Fade out +// ----------------------------------------------------------------------------------------------------- +const fadeOut = trigger('fadeOut', [ + state( + '*', + style({ + opacity: 1, + }) + ), + + state( + 'void', + style({ + opacity: 0, + }) + ), + + // Prevent the transition if the state is false + transition('false => void', []), + + // Transition + transition('* => void', animate('{{timings}}'), { + params: { + timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`, + }, + }), +]); + +// ----------------------------------------------------------------------------------------------------- +// @ Fade out top +// ----------------------------------------------------------------------------------------------------- +const fadeOutTop = trigger('fadeOutTop', [ + state( + '*', + style({ + opacity: 1, + transform: 'translate3d(0, 0, 0)', + }) + ), + + state( + 'void', + style({ + opacity: 0, + transform: 'translate3d(0, -100%, 0)', + }) + ), + + // Prevent the transition if the state is false + transition('false => void', []), + + // Transition + transition('* => void', animate('{{timings}}'), { + params: { + timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`, + }, + }), +]); + +// ----------------------------------------------------------------------------------------------------- +// @ Fade out bottom +// ----------------------------------------------------------------------------------------------------- +const fadeOutBottom = trigger('fadeOutBottom', [ + state( + '*', + style({ + opacity: 1, + transform: 'translate3d(0, 0, 0)', + }) + ), + + state( + 'void', + style({ + opacity: 0, + transform: 'translate3d(0, 100%, 0)', + }) + ), + + // Prevent the transition if the state is false + transition('false => void', []), + + // Transition + transition('* => void', animate('{{timings}}'), { + params: { + timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`, + }, + }), +]); + +// ----------------------------------------------------------------------------------------------------- +// @ Fade out left +// ----------------------------------------------------------------------------------------------------- +const fadeOutLeft = trigger('fadeOutLeft', [ + state( + '*', + style({ + opacity: 1, + transform: 'translate3d(0, 0, 0)', + }) + ), + + state( + 'void', + style({ + opacity: 0, + transform: 'translate3d(-100%, 0, 0)', + }) + ), + + // Prevent the transition if the state is false + transition('false => void', []), + + // Transition + transition('* => void', animate('{{timings}}'), { + params: { + timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`, + }, + }), +]); + +// ----------------------------------------------------------------------------------------------------- +// @ Fade out right +// ----------------------------------------------------------------------------------------------------- +const fadeOutRight = trigger('fadeOutRight', [ + state( + '*', + style({ + opacity: 1, + transform: 'translate3d(0, 0, 0)', + }) + ), + + state( + 'void', + style({ + opacity: 0, + transform: 'translate3d(100%, 0, 0)', + }) + ), + + // Prevent the transition if the state is false + transition('false => void', []), + + // Transition + transition('* => void', animate('{{timings}}'), { + params: { + timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`, + }, + }), +]); + +export { + fadeIn, + fadeInBottom, + fadeInLeft, + fadeInRight, + fadeInTop, + fadeOut, + fadeOutBottom, + fadeOutLeft, + fadeOutRight, + fadeOutTop, +}; diff --git a/frontend/src/@fuse/animations/index.ts b/frontend/src/@fuse/animations/index.ts new file mode 100644 index 00000000..e3669783 --- /dev/null +++ b/frontend/src/@fuse/animations/index.ts @@ -0,0 +1 @@ +export * from '@fuse/animations/public-api'; diff --git a/frontend/src/@fuse/animations/public-api.ts b/frontend/src/@fuse/animations/public-api.ts new file mode 100644 index 00000000..cbf25af5 --- /dev/null +++ b/frontend/src/@fuse/animations/public-api.ts @@ -0,0 +1,50 @@ +import { expandCollapse } from '@fuse/animations/expand-collapse'; +import { + fadeIn, + fadeInBottom, + fadeInLeft, + fadeInRight, + fadeInTop, + fadeOut, + fadeOutBottom, + fadeOutLeft, + fadeOutRight, + fadeOutTop, +} from '@fuse/animations/fade'; +import { shake } from '@fuse/animations/shake'; +import { + slideInBottom, + slideInLeft, + slideInRight, + slideInTop, + slideOutBottom, + slideOutLeft, + slideOutRight, + slideOutTop, +} from '@fuse/animations/slide'; +import { zoomIn, zoomOut } from '@fuse/animations/zoom'; + +export const fuseAnimations = [ + expandCollapse, + fadeIn, + fadeInTop, + fadeInBottom, + fadeInLeft, + fadeInRight, + fadeOut, + fadeOutTop, + fadeOutBottom, + fadeOutLeft, + fadeOutRight, + shake, + slideInTop, + slideInBottom, + slideInLeft, + slideInRight, + slideOutTop, + slideOutBottom, + slideOutLeft, + slideOutRight, + zoomIn, + zoomOut, +]; diff --git a/frontend/src/@fuse/animations/shake.ts b/frontend/src/@fuse/animations/shake.ts new file mode 100644 index 00000000..bb7ef616 --- /dev/null +++ b/frontend/src/@fuse/animations/shake.ts @@ -0,0 +1,78 @@ +import { + animate, + keyframes, + style, + transition, + trigger, +} from '@angular/animations'; + +// ----------------------------------------------------------------------------------------------------- +// @ Shake +// ----------------------------------------------------------------------------------------------------- +const shake = trigger('shake', [ + // Prevent the transition if the state is false + transition('void => false', []), + + // Transition + transition( + 'void => *, * => true', + [ + animate( + '{{timings}}', + keyframes([ + style({ + transform: 'translate3d(0, 0, 0)', + offset: 0, + }), + style({ + transform: 'translate3d(-10px, 0, 0)', + offset: 0.1, + }), + style({ + transform: 'translate3d(10px, 0, 0)', + offset: 0.2, + }), + style({ + transform: 'translate3d(-10px, 0, 0)', + offset: 0.3, + }), + style({ + transform: 'translate3d(10px, 0, 0)', + offset: 0.4, + }), + style({ + transform: 'translate3d(-10px, 0, 0)', + offset: 0.5, + }), + style({ + transform: 'translate3d(10px, 0, 0)', + offset: 0.6, + }), + style({ + transform: 'translate3d(-10px, 0, 0)', + offset: 0.7, + }), + style({ + transform: 'translate3d(10px, 0, 0)', + offset: 0.8, + }), + style({ + transform: 'translate3d(-10px, 0, 0)', + offset: 0.9, + }), + style({ + transform: 'translate3d(0, 0, 0)', + offset: 1, + }), + ]) + ), + ], + { + params: { + timings: '0.8s cubic-bezier(0.455, 0.03, 0.515, 0.955)', + }, + } + ), +]); + +export { shake }; diff --git a/frontend/src/@fuse/animations/slide.ts b/frontend/src/@fuse/animations/slide.ts new file mode 100644 index 00000000..aaf4bf07 --- /dev/null +++ b/frontend/src/@fuse/animations/slide.ts @@ -0,0 +1,254 @@ +import { + animate, + state, + style, + transition, + trigger, +} from '@angular/animations'; +import { + FuseAnimationCurves, + FuseAnimationDurations, +} from '@fuse/animations/defaults'; + +// ----------------------------------------------------------------------------------------------------- +// @ Slide in top +// ----------------------------------------------------------------------------------------------------- +const slideInTop = trigger('slideInTop', [ + state( + 'void', + style({ + transform: 'translate3d(0, -100%, 0)', + }) + ), + + state( + '*', + style({ + transform: 'translate3d(0, 0, 0)', + }) + ), + + // Prevent the transition if the state is false + transition('void => false', []), + + // Transition + transition('void => *', animate('{{timings}}'), { + params: { + timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`, + }, + }), +]); + +// ----------------------------------------------------------------------------------------------------- +// @ Slide in bottom +// ----------------------------------------------------------------------------------------------------- +const slideInBottom = trigger('slideInBottom', [ + state( + 'void', + style({ + transform: 'translate3d(0, 100%, 0)', + }) + ), + + state( + '*', + style({ + transform: 'translate3d(0, 0, 0)', + }) + ), + + // Prevent the transition if the state is false + transition('void => false', []), + + // Transition + transition('void => *', animate('{{timings}}'), { + params: { + timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`, + }, + }), +]); + +// ----------------------------------------------------------------------------------------------------- +// @ Slide in left +// ----------------------------------------------------------------------------------------------------- +const slideInLeft = trigger('slideInLeft', [ + state( + 'void', + style({ + transform: 'translate3d(-100%, 0, 0)', + }) + ), + + state( + '*', + style({ + transform: 'translate3d(0, 0, 0)', + }) + ), + + // Prevent the transition if the state is false + transition('void => false', []), + + // Transition + transition('void => *', animate('{{timings}}'), { + params: { + timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`, + }, + }), +]); + +// ----------------------------------------------------------------------------------------------------- +// @ Slide in right +// ----------------------------------------------------------------------------------------------------- +const slideInRight = trigger('slideInRight', [ + state( + 'void', + style({ + transform: 'translate3d(100%, 0, 0)', + }) + ), + + state( + '*', + style({ + transform: 'translate3d(0, 0, 0)', + }) + ), + + // Prevent the transition if the state is false + transition('void => false', []), + + // Transition + transition('void => *', animate('{{timings}}'), { + params: { + timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`, + }, + }), +]); + +// ----------------------------------------------------------------------------------------------------- +// @ Slide out top +// ----------------------------------------------------------------------------------------------------- +const slideOutTop = trigger('slideOutTop', [ + state( + '*', + style({ + transform: 'translate3d(0, 0, 0)', + }) + ), + + state( + 'void', + style({ + transform: 'translate3d(0, -100%, 0)', + }) + ), + + // Prevent the transition if the state is false + transition('false => void', []), + + // Transition + transition('* => void', animate('{{timings}}'), { + params: { + timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`, + }, + }), +]); + +// ----------------------------------------------------------------------------------------------------- +// @ Slide out bottom +// ----------------------------------------------------------------------------------------------------- +const slideOutBottom = trigger('slideOutBottom', [ + state( + '*', + style({ + transform: 'translate3d(0, 0, 0)', + }) + ), + + state( + 'void', + style({ + transform: 'translate3d(0, 100%, 0)', + }) + ), + + // Prevent the transition if the state is false + transition('false => void', []), + + // Transition + transition('* => void', animate('{{timings}}'), { + params: { + timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`, + }, + }), +]); + +// ----------------------------------------------------------------------------------------------------- +// @ Slide out left +// ----------------------------------------------------------------------------------------------------- +const slideOutLeft = trigger('slideOutLeft', [ + state( + '*', + style({ + transform: 'translate3d(0, 0, 0)', + }) + ), + + state( + 'void', + style({ + transform: 'translate3d(-100%, 0, 0)', + }) + ), + + // Prevent the transition if the state is false + transition('false => void', []), + + // Transition + transition('* => void', animate('{{timings}}'), { + params: { + timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`, + }, + }), +]); + +// ----------------------------------------------------------------------------------------------------- +// @ Slide out right +// ----------------------------------------------------------------------------------------------------- +const slideOutRight = trigger('slideOutRight', [ + state( + '*', + style({ + transform: 'translate3d(0, 0, 0)', + }) + ), + + state( + 'void', + style({ + transform: 'translate3d(100%, 0, 0)', + }) + ), + + // Prevent the transition if the state is false + transition('false => void', []), + + // Transition + transition('* => void', animate('{{timings}}'), { + params: { + timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`, + }, + }), +]); + +export { + slideInBottom, + slideInLeft, + slideInRight, + slideInTop, + slideOutBottom, + slideOutLeft, + slideOutRight, + slideOutTop, +}; diff --git a/frontend/src/@fuse/animations/zoom.ts b/frontend/src/@fuse/animations/zoom.ts new file mode 100644 index 00000000..b039ec4a --- /dev/null +++ b/frontend/src/@fuse/animations/zoom.ts @@ -0,0 +1,75 @@ +import { + animate, + state, + style, + transition, + trigger, +} from '@angular/animations'; +import { + FuseAnimationCurves, + FuseAnimationDurations, +} from '@fuse/animations/defaults'; + +// ----------------------------------------------------------------------------------------------------- +// @ Zoom in +// ----------------------------------------------------------------------------------------------------- +const zoomIn = trigger('zoomIn', [ + state( + 'void', + style({ + opacity: 0, + transform: 'scale(0.5)', + }) + ), + + state( + '*', + style({ + opacity: 1, + transform: 'scale(1)', + }) + ), + + // Prevent the transition if the state is false + transition('void => false', []), + + // Transition + transition('void => *', animate('{{timings}}'), { + params: { + timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`, + }, + }), +]); + +// ----------------------------------------------------------------------------------------------------- +// @ Zoom out +// ----------------------------------------------------------------------------------------------------- +const zoomOut = trigger('zoomOut', [ + state( + '*', + style({ + opacity: 1, + transform: 'scale(1)', + }) + ), + + state( + 'void', + style({ + opacity: 0, + transform: 'scale(0.5)', + }) + ), + + // Prevent the transition if the state is false + transition('false => void', []), + + // Transition + transition('* => void', animate('{{timings}}'), { + params: { + timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`, + }, + }), +]); + +export { zoomIn, zoomOut }; diff --git a/frontend/src/@fuse/components/alert/alert.component.html b/frontend/src/@fuse/components/alert/alert.component.html new file mode 100644 index 00000000..0d512055 --- /dev/null +++ b/frontend/src/@fuse/components/alert/alert.component.html @@ -0,0 +1,93 @@ +@if (!dismissible || (dismissible && !dismissed)) { +
+ + @if (appearance === 'border') { +
+ } + + + @if (showIcon) { +
+ +
+ +
+ + +
+ @if (type === 'primary') { + + } + + @if (type === 'accent') { + + } + + @if (type === 'warn') { + + } + + @if (type === 'basic') { + + } + + @if (type === 'info') { + + } + + @if (type === 'success') { + + } + + @if (type === 'warning') { + + } + + @if (type === 'error') { + + } +
+
+ } + + +
+
+ +
+ +
+ +
+
+ + + +
+} diff --git a/frontend/src/@fuse/components/alert/alert.component.scss b/frontend/src/@fuse/components/alert/alert.component.scss new file mode 100644 index 00000000..10ce2e37 --- /dev/null +++ b/frontend/src/@fuse/components/alert/alert.component.scss @@ -0,0 +1,1290 @@ +fuse-alert { + display: block; + + /* Common */ + .fuse-alert-container { + position: relative; + display: flex; + padding: 16px; + font-size: 14px; + line-height: 1; + + /* All icons */ + .mat-icon { + color: currentColor !important; + } + + /* Icon */ + .fuse-alert-icon { + display: flex; + align-items: flex-start; + + .fuse-alert-custom-icon, + .fuse-alert-default-icon { + display: none; + align-items: center; + justify-content: center; + border-radius: 50%; + + &:not(:empty) { + display: flex; + margin-right: 12px; + } + } + + .fuse-alert-default-icon { + .mat-icon { + @apply icon-size-5; + } + } + + .fuse-alert-custom-icon { + display: none; + + &:not(:empty) { + display: flex; + + + .fuse-alert-default-icon { + display: none; + } + } + } + } + + /* Content */ + .fuse-alert-content { + display: flex; + flex-direction: column; + justify-content: center; + line-height: 1; + + /* Title */ + .fuse-alert-title { + display: none; + font-weight: 600; + line-height: 20px; + + &:not(:empty) { + display: block; + + /* Alert that comes after the title */ + + .fuse-alert-message { + &:not(:empty) { + margin-top: 4px; + } + } + } + } + + /* Alert */ + .fuse-alert-message { + display: none; + line-height: 20px; + + &:not(:empty) { + display: block; + } + } + } + + /* Dismiss button */ + .fuse-alert-dismiss-button { + position: absolute; + top: 10px; + right: 10px; + width: 32px !important; + min-width: 32px !important; + height: 32px !important; + min-height: 32px !important; + line-height: 32px !important; + + .mat-icon { + @apply icon-size-4; + } + } + } + + /* Dismissible */ + &.fuse-alert-dismissible { + .fuse-alert-container { + .fuse-alert-content { + margin-right: 32px; + } + } + } + + &:not(.fuse-alert-dismissible) { + .fuse-alert-container { + .fuse-alert-dismiss-button { + display: none !important; + } + } + } + + /* Border */ + &.fuse-alert-appearance-border { + .fuse-alert-container { + position: relative; + overflow: hidden; + border-radius: 6px; + @apply bg-card shadow-md; + + .fuse-alert-border { + position: absolute; + left: 0; + top: 0; + bottom: 0; + width: 4px; + } + + .fuse-alert-message { + @apply text-gray-600; + } + } + + /* Primary */ + &.fuse-alert-type-primary { + .fuse-alert-container { + .fuse-alert-border { + @apply bg-primary; + } + + .fuse-alert-title, + .fuse-alert-icon { + @apply text-primary; + } + + .dark & { + @apply bg-gray-700; + + .fuse-alert-border { + @apply bg-primary-400; + } + + .fuse-alert-title, + .fuse-alert-icon { + @apply text-primary-400; + } + + .fuse-alert-message { + @apply text-gray-300; + } + + code { + @apply bg-gray-400 text-gray-800; + } + } + } + } + + /* Accent */ + &.fuse-alert-type-accent { + .fuse-alert-container { + .fuse-alert-border { + @apply bg-accent; + } + + .fuse-alert-title, + .fuse-alert-icon { + @apply text-accent; + } + + .dark & { + @apply bg-gray-700; + + .fuse-alert-border { + @apply bg-accent-400; + } + + .fuse-alert-title, + .fuse-alert-icon { + @apply text-accent-400; + } + + .fuse-alert-message { + @apply text-gray-300; + } + + code { + @apply bg-gray-400 text-gray-800; + } + } + } + } + + /* Warn */ + &.fuse-alert-type-warn { + .fuse-alert-container { + .fuse-alert-border { + @apply bg-warn; + } + + .fuse-alert-title, + .fuse-alert-icon { + @apply text-warn; + } + + .dark & { + @apply bg-gray-700; + + .fuse-alert-border { + @apply bg-warn-400; + } + + .fuse-alert-title, + .fuse-alert-icon { + @apply text-warn-400; + } + + .fuse-alert-message { + @apply text-gray-300; + } + + code { + @apply bg-gray-400 text-gray-800; + } + } + } + } + + /* Basic */ + &.fuse-alert-type-basic { + .fuse-alert-container { + .fuse-alert-border { + @apply bg-gray-600; + } + + .fuse-alert-title, + .fuse-alert-icon { + @apply text-gray-600; + } + + .dark & { + @apply bg-gray-700; + + .fuse-alert-border { + @apply bg-gray-400; + } + + .fuse-alert-title, + .fuse-alert-icon { + @apply text-gray-400; + } + + .fuse-alert-message { + @apply text-gray-300; + } + + code { + @apply bg-gray-400 text-gray-800; + } + } + } + } + + /* Info */ + &.fuse-alert-type-info { + .fuse-alert-container { + .fuse-alert-border { + @apply bg-blue-600; + } + + .fuse-alert-title, + .fuse-alert-icon { + @apply text-blue-700; + } + + .dark & { + @apply bg-gray-700; + + .fuse-alert-border { + @apply bg-blue-400; + } + + .fuse-alert-title, + .fuse-alert-icon { + @apply text-blue-400; + } + + .fuse-alert-message { + @apply text-gray-300; + } + + code { + @apply bg-gray-400 text-gray-800; + } + } + } + } + + /* Success */ + &.fuse-alert-type-success { + .fuse-alert-container { + .fuse-alert-border { + @apply bg-green-500; + } + + .fuse-alert-title, + .fuse-alert-icon { + @apply text-green-500; + } + + .dark & { + @apply bg-gray-700; + + .fuse-alert-border { + @apply bg-green-400; + } + + .fuse-alert-title, + .fuse-alert-icon { + @apply text-green-400; + } + + .fuse-alert-message { + @apply text-gray-300; + } + + code { + @apply bg-gray-400 text-gray-800; + } + } + } + } + + /* Warning */ + &.fuse-alert-type-warning { + .fuse-alert-container { + .fuse-alert-border { + @apply bg-amber-500; + } + + .fuse-alert-title, + .fuse-alert-icon { + @apply text-amber-500; + } + + .dark & { + @apply bg-gray-700; + + .fuse-alert-border { + @apply bg-amber-400; + } + + .fuse-alert-title, + .fuse-alert-icon { + @apply text-amber-400; + } + + .fuse-alert-message { + @apply text-gray-300; + } + + code { + @apply bg-gray-400 text-gray-800; + } + } + } + } + + /* Error */ + &.fuse-alert-type-error { + .fuse-alert-container { + .fuse-alert-border { + @apply bg-red-600; + } + + .fuse-alert-title, + .fuse-alert-icon { + @apply text-red-700; + } + + .dark & { + @apply bg-gray-700; + + .fuse-alert-border { + @apply bg-red-400; + } + + .fuse-alert-title, + .fuse-alert-icon { + @apply text-red-400; + } + + .fuse-alert-message { + @apply text-gray-300; + } + + code { + @apply bg-gray-400 text-gray-800; + } + } + } + } + } + + /* Fill */ + &.fuse-alert-appearance-fill { + .fuse-alert-container { + border-radius: 6px; + + .fuse-alert-dismiss-button { + @apply text-white; + } + } + + /* Primary */ + &.fuse-alert-type-primary { + .fuse-alert-container { + @apply bg-primary-600; + + .fuse-alert-icon { + @apply text-white; + } + + .fuse-alert-title { + @apply text-white; + } + + .fuse-alert-message { + @apply text-primary-100; + } + + code { + @apply bg-primary-200 text-primary-800; + } + } + } + + /* Accent */ + &.fuse-alert-type-accent { + .fuse-alert-container { + @apply bg-accent-600; + + .fuse-alert-icon { + @apply text-white; + } + + .fuse-alert-title { + @apply text-white; + } + + .fuse-alert-message { + @apply text-accent-100; + } + + code { + @apply bg-accent-200 text-accent-800; + } + } + } + + /* Warn */ + &.fuse-alert-type-warn { + .fuse-alert-container { + @apply bg-warn-600; + + .fuse-alert-icon { + @apply text-white; + } + + .fuse-alert-title { + @apply text-white; + } + + .fuse-alert-message { + @apply text-warn-100; + } + + code { + @apply bg-warn-200 text-warn-800; + } + } + } + + /* Basic */ + &.fuse-alert-type-basic { + .fuse-alert-container { + @apply bg-gray-600; + + .fuse-alert-icon { + @apply text-white; + } + + .fuse-alert-title { + @apply text-white; + } + + .fuse-alert-message { + @apply text-gray-100; + } + + code { + @apply bg-gray-200 text-gray-800; + } + } + } + + /* Info */ + &.fuse-alert-type-info { + .fuse-alert-container { + @apply bg-blue-600; + + .fuse-alert-icon { + @apply text-white; + } + + .fuse-alert-title { + @apply text-white; + } + + .fuse-alert-message { + @apply text-blue-100; + } + + code { + @apply bg-blue-200 text-blue-800; + } + } + } + + /* Success */ + &.fuse-alert-type-success { + .fuse-alert-container { + @apply bg-green-600; + + .fuse-alert-icon { + @apply text-white; + } + + .fuse-alert-title { + @apply text-white; + } + + .fuse-alert-message { + @apply text-green-100; + } + + code { + @apply bg-green-200 text-gray-800; + } + } + } + + /* Warning */ + &.fuse-alert-type-warning { + .fuse-alert-container { + @apply bg-amber-500; + + .fuse-alert-icon { + @apply text-white; + } + + .fuse-alert-title { + @apply text-white; + } + + .fuse-alert-message { + @apply text-amber-100; + } + + code { + @apply bg-amber-200 text-amber-800; + } + } + } + + /* Error */ + &.fuse-alert-type-error { + .fuse-alert-container { + @apply bg-red-600; + + .fuse-alert-icon { + @apply text-white; + } + + .fuse-alert-title { + @apply text-white; + } + + .fuse-alert-message { + @apply text-red-100; + } + + code { + @apply bg-red-200 text-red-800; + } + } + } + } + + /* Outline */ + &.fuse-alert-appearance-outline { + .fuse-alert-container { + border-radius: 6px; + } + + /* Primary */ + &.fuse-alert-type-primary { + .fuse-alert-container { + @apply bg-primary-50 ring-1 ring-inset ring-primary-400; + + .fuse-alert-icon { + @apply text-primary-600; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-primary-900; + } + + .fuse-alert-message { + @apply text-primary-700; + } + + code { + @apply bg-primary-200 text-primary-800; + } + + .dark & { + @apply bg-primary-600; + + .fuse-alert-icon { + @apply text-white; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-white; + } + + .fuse-alert-message { + @apply text-primary-200; + } + } + } + } + + /* Accent */ + &.fuse-alert-type-accent { + .fuse-alert-container { + @apply bg-accent-100 ring-1 ring-inset ring-accent-400; + + .fuse-alert-icon { + @apply text-accent-600; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-accent-900; + } + + .fuse-alert-message { + @apply text-accent-700; + } + + code { + @apply bg-accent-200 text-accent-800; + } + + .dark & { + @apply bg-accent-600; + + .fuse-alert-icon { + @apply text-white; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-white; + } + + .fuse-alert-message { + @apply text-accent-200; + } + } + } + } + + /* Warn */ + &.fuse-alert-type-warn { + .fuse-alert-container { + @apply bg-warn-50 ring-1 ring-inset ring-warn-400; + + .fuse-alert-icon { + @apply text-warn-600; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-warn-900; + } + + .fuse-alert-message { + @apply text-warn-700; + } + + code { + @apply bg-warn-200 text-warn-800; + } + + .dark & { + @apply bg-warn-600; + + .fuse-alert-icon { + @apply text-white; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-white; + } + + .fuse-alert-message { + @apply text-warn-200; + } + } + } + } + + /* Basic */ + &.fuse-alert-type-basic { + .fuse-alert-container { + @apply bg-gray-100 ring-1 ring-inset ring-gray-400; + + .fuse-alert-icon { + @apply text-gray-600; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-gray-900; + } + + .fuse-alert-message { + @apply text-gray-700; + } + + code { + @apply bg-gray-200 text-gray-800; + } + + .dark & { + @apply bg-gray-600; + + .fuse-alert-icon { + @apply text-white; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-white; + } + + .fuse-alert-message { + @apply text-gray-200; + } + } + } + } + + /* Info */ + &.fuse-alert-type-info { + .fuse-alert-container { + @apply bg-blue-50 ring-1 ring-inset ring-blue-400; + + .fuse-alert-icon { + @apply text-blue-600; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-blue-900; + } + + .fuse-alert-message { + @apply text-blue-700; + } + + code { + @apply bg-blue-200 text-blue-800; + } + + .dark & { + @apply bg-blue-600; + + .fuse-alert-icon { + @apply text-white; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-white; + } + + .fuse-alert-message { + @apply text-blue-200; + } + } + } + } + + /* Success */ + &.fuse-alert-type-success { + .fuse-alert-container { + @apply bg-green-50 ring-1 ring-inset ring-green-400; + + .fuse-alert-icon { + @apply text-green-600; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-green-900; + } + + .fuse-alert-message { + @apply text-green-700; + } + + code { + @apply bg-green-200 text-green-800; + } + + .dark & { + @apply bg-green-600; + + .fuse-alert-icon { + @apply text-white; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-white; + } + + .fuse-alert-message { + @apply text-green-200; + } + } + } + } + + /* Warning */ + &.fuse-alert-type-warning { + .fuse-alert-container { + @apply bg-amber-50 ring-1 ring-inset ring-amber-400; + + .fuse-alert-icon { + @apply text-amber-600; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-amber-900; + } + + .fuse-alert-message { + @apply text-amber-700; + } + + code { + @apply bg-amber-200 text-amber-800; + } + + .dark & { + @apply bg-amber-600; + + .fuse-alert-icon { + @apply text-white; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-white; + } + + .fuse-alert-message { + @apply text-amber-200; + } + } + } + } + + /* Error */ + &.fuse-alert-type-error { + .fuse-alert-container { + @apply bg-red-50 ring-1 ring-inset ring-red-400; + + .fuse-alert-icon { + @apply text-red-600; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-red-900; + } + + .fuse-alert-message { + @apply text-red-700; + } + + code { + @apply bg-red-200 text-red-800; + } + + .dark & { + @apply bg-red-600; + + .fuse-alert-icon { + @apply text-white; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-white; + } + + .fuse-alert-message { + @apply text-red-200; + } + } + } + } + } + + /* Soft */ + &.fuse-alert-appearance-soft { + .fuse-alert-container { + border-radius: 6px; + } + + /* Primary */ + &.fuse-alert-type-primary { + .fuse-alert-container { + @apply bg-primary-50; + + .fuse-alert-icon { + @apply text-primary-600; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-primary-900; + } + + .fuse-alert-message { + @apply text-primary-700; + } + + code { + @apply bg-primary-200 text-primary-800; + } + + .dark & { + @apply bg-primary-600; + + .fuse-alert-icon { + @apply text-white; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-white; + } + + .fuse-alert-message { + @apply text-primary-200; + } + } + } + } + + /* Accent */ + &.fuse-alert-type-accent { + .fuse-alert-container { + @apply bg-accent-100; + + .fuse-alert-icon { + @apply text-accent-600; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-accent-900; + } + + .fuse-alert-message { + @apply text-accent-700; + } + + code { + @apply bg-accent-200 text-accent-800; + } + + .dark & { + @apply bg-accent-600; + + .fuse-alert-icon { + @apply text-white; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-white; + } + + .fuse-alert-message { + @apply text-accent-200; + } + } + } + } + + /* Warn */ + &.fuse-alert-type-warn { + .fuse-alert-container { + @apply bg-warn-50; + + .fuse-alert-icon { + @apply text-warn-600; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-warn-900; + } + + .fuse-alert-message { + @apply text-warn-700; + } + + code { + @apply bg-warn-200 text-warn-800; + } + + .dark & { + @apply bg-warn-600; + + .fuse-alert-icon { + @apply text-white; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-white; + } + + .fuse-alert-message { + @apply text-warn-200; + } + } + } + } + + /* Basic */ + &.fuse-alert-type-basic { + .fuse-alert-container { + @apply bg-gray-100; + + .fuse-alert-icon { + @apply text-gray-600; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-gray-900; + } + + .fuse-alert-message { + @apply text-gray-700; + } + + code { + @apply bg-gray-200 text-gray-800; + } + + .dark & { + @apply bg-gray-600; + + .fuse-alert-icon { + @apply text-white; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-white; + } + + .fuse-alert-message { + @apply text-gray-200; + } + } + } + } + + /* Info */ + &.fuse-alert-type-info { + .fuse-alert-container { + @apply bg-blue-50; + + .fuse-alert-icon { + @apply text-blue-600; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-blue-900; + } + + .fuse-alert-message { + @apply text-blue-700; + } + + code { + @apply bg-blue-200 text-blue-800; + } + + .dark & { + @apply bg-blue-600; + + .fuse-alert-icon { + @apply text-white; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-white; + } + + .fuse-alert-message { + @apply text-blue-200; + } + } + } + } + + /* Success */ + &.fuse-alert-type-success { + .fuse-alert-container { + @apply bg-green-50; + + .fuse-alert-icon { + @apply text-green-600; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-green-900; + } + + .fuse-alert-message { + @apply text-green-700; + } + + code { + @apply bg-green-200 text-green-800; + } + + .dark & { + @apply bg-green-600; + + .fuse-alert-icon { + @apply text-white; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-white; + } + + .fuse-alert-message { + @apply text-green-200; + } + } + } + } + + /* Warning */ + &.fuse-alert-type-warning { + .fuse-alert-container { + @apply bg-amber-50; + + .fuse-alert-icon { + @apply text-amber-600; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-amber-900; + } + + .fuse-alert-message { + @apply text-amber-700; + } + + code { + @apply bg-amber-200 text-amber-800; + } + + .dark & { + @apply bg-amber-600; + + .fuse-alert-icon { + @apply text-white; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-white; + } + + .fuse-alert-message { + @apply text-amber-200; + } + } + } + } + + /* Error */ + &.fuse-alert-type-error { + .fuse-alert-container { + @apply bg-red-50; + + .fuse-alert-icon { + @apply text-red-600; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-red-900; + } + + .fuse-alert-message { + @apply text-red-700; + } + + code { + @apply bg-red-200 text-red-800; + } + + .dark & { + @apply bg-red-600; + + .fuse-alert-icon { + @apply text-white; + } + + .fuse-alert-title, + .fuse-alert-dismiss-button { + @apply text-white; + } + + .fuse-alert-message { + @apply text-red-200; + } + } + } + } + } +} diff --git a/frontend/src/@fuse/components/alert/alert.component.ts b/frontend/src/@fuse/components/alert/alert.component.ts new file mode 100644 index 00000000..7c6d2c21 --- /dev/null +++ b/frontend/src/@fuse/components/alert/alert.component.ts @@ -0,0 +1,220 @@ +import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion'; + +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + EventEmitter, + HostBinding, + Input, + OnChanges, + OnDestroy, + OnInit, + Output, + SimpleChanges, + ViewEncapsulation, + inject, +} from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { fuseAnimations } from '@fuse/animations'; +import { FuseAlertService } from '@fuse/components/alert/alert.service'; +import { + FuseAlertAppearance, + FuseAlertType, +} from '@fuse/components/alert/alert.types'; +import { FuseUtilsService } from '@fuse/services/utils/utils.service'; +import { Subject, filter, takeUntil } from 'rxjs'; + +@Component({ + selector: 'fuse-alert', + templateUrl: './alert.component.html', + styleUrls: ['./alert.component.scss'], + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + animations: fuseAnimations, + exportAs: 'fuseAlert', + standalone: true, + imports: [MatIconModule, MatButtonModule], +}) +export class FuseAlertComponent implements OnChanges, OnInit, OnDestroy { + /* eslint-disable @typescript-eslint/naming-convention */ + static ngAcceptInputType_dismissible: BooleanInput; + static ngAcceptInputType_dismissed: BooleanInput; + static ngAcceptInputType_showIcon: BooleanInput; + /* eslint-enable @typescript-eslint/naming-convention */ + + private _changeDetectorRef = inject(ChangeDetectorRef); + private _fuseAlertService = inject(FuseAlertService); + private _fuseUtilsService = inject(FuseUtilsService); + + @Input() appearance: FuseAlertAppearance = 'soft'; + @Input() dismissed: boolean = false; + @Input() dismissible: boolean = false; + @Input() name: string = this._fuseUtilsService.randomId(); + @Input() showIcon: boolean = true; + @Input() type: FuseAlertType = 'primary'; + @Output() readonly dismissedChanged: EventEmitter = + new EventEmitter(); + + private _unsubscribeAll: Subject = new Subject(); + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Host binding for component classes + */ + @HostBinding('class') get classList(): any { + /* eslint-disable @typescript-eslint/naming-convention */ + return { + 'fuse-alert-appearance-border': this.appearance === 'border', + 'fuse-alert-appearance-fill': this.appearance === 'fill', + 'fuse-alert-appearance-outline': this.appearance === 'outline', + 'fuse-alert-appearance-soft': this.appearance === 'soft', + 'fuse-alert-dismissed': this.dismissed, + 'fuse-alert-dismissible': this.dismissible, + 'fuse-alert-show-icon': this.showIcon, + 'fuse-alert-type-primary': this.type === 'primary', + 'fuse-alert-type-accent': this.type === 'accent', + 'fuse-alert-type-warn': this.type === 'warn', + 'fuse-alert-type-basic': this.type === 'basic', + 'fuse-alert-type-info': this.type === 'info', + 'fuse-alert-type-success': this.type === 'success', + 'fuse-alert-type-warning': this.type === 'warning', + 'fuse-alert-type-error': this.type === 'error', + }; + /* eslint-enable @typescript-eslint/naming-convention */ + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On changes + * + * @param changes + */ + ngOnChanges(changes: SimpleChanges): void { + // Dismissed + if ('dismissed' in changes) { + // Coerce the value to a boolean + this.dismissed = coerceBooleanProperty( + changes.dismissed.currentValue + ); + + // Dismiss/show the alert + this._toggleDismiss(this.dismissed); + } + + // Dismissible + if ('dismissible' in changes) { + // Coerce the value to a boolean + this.dismissible = coerceBooleanProperty( + changes.dismissible.currentValue + ); + } + + // Show icon + if ('showIcon' in changes) { + // Coerce the value to a boolean + this.showIcon = coerceBooleanProperty( + changes.showIcon.currentValue + ); + } + } + + /** + * On init + */ + ngOnInit(): void { + // Subscribe to the dismiss calls + this._fuseAlertService.onDismiss + .pipe( + filter((name) => this.name === name), + takeUntil(this._unsubscribeAll) + ) + .subscribe(() => { + // Dismiss the alert + this.dismiss(); + }); + + // Subscribe to the show calls + this._fuseAlertService.onShow + .pipe( + filter((name) => this.name === name), + takeUntil(this._unsubscribeAll) + ) + .subscribe(() => { + // Show the alert + this.show(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Dismiss the alert + */ + dismiss(): void { + // Return if the alert is already dismissed + if (this.dismissed) { + return; + } + + // Dismiss the alert + this._toggleDismiss(true); + } + + /** + * Show the dismissed alert + */ + show(): void { + // Return if the alert is already showing + if (!this.dismissed) { + return; + } + + // Show the alert + this._toggleDismiss(false); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Private methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Dismiss/show the alert + * + * @param dismissed + * @private + */ + private _toggleDismiss(dismissed: boolean): void { + // Return if the alert is not dismissible + if (!this.dismissible) { + return; + } + + // Set the dismissed + this.dismissed = dismissed; + + // Execute the observable + this.dismissedChanged.next(this.dismissed); + + // Notify the change detector + this._changeDetectorRef.markForCheck(); + } +} diff --git a/frontend/src/@fuse/components/alert/alert.service.ts b/frontend/src/@fuse/components/alert/alert.service.ts new file mode 100644 index 00000000..bb92c3e4 --- /dev/null +++ b/frontend/src/@fuse/components/alert/alert.service.ts @@ -0,0 +1,63 @@ +import { Injectable } from '@angular/core'; +import { Observable, ReplaySubject } from 'rxjs'; + +@Injectable({ providedIn: 'root' }) +export class FuseAlertService { + private readonly _onDismiss: ReplaySubject = + new ReplaySubject(1); + private readonly _onShow: ReplaySubject = new ReplaySubject( + 1 + ); + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Getter for onDismiss + */ + get onDismiss(): Observable { + return this._onDismiss.asObservable(); + } + + /** + * Getter for onShow + */ + get onShow(): Observable { + return this._onShow.asObservable(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Dismiss the alert + * + * @param name + */ + dismiss(name: string): void { + // Return if the name is not provided + if (!name) { + return; + } + + // Execute the observable + this._onDismiss.next(name); + } + + /** + * Show the dismissed alert + * + * @param name + */ + show(name: string): void { + // Return if the name is not provided + if (!name) { + return; + } + + // Execute the observable + this._onShow.next(name); + } +} diff --git a/frontend/src/@fuse/components/alert/alert.types.ts b/frontend/src/@fuse/components/alert/alert.types.ts new file mode 100644 index 00000000..010b59f9 --- /dev/null +++ b/frontend/src/@fuse/components/alert/alert.types.ts @@ -0,0 +1,11 @@ +export type FuseAlertAppearance = 'border' | 'fill' | 'outline' | 'soft'; + +export type FuseAlertType = + | 'primary' + | 'accent' + | 'warn' + | 'basic' + | 'info' + | 'success' + | 'warning' + | 'error'; diff --git a/frontend/src/@fuse/components/alert/index.ts b/frontend/src/@fuse/components/alert/index.ts new file mode 100644 index 00000000..c18a807a --- /dev/null +++ b/frontend/src/@fuse/components/alert/index.ts @@ -0,0 +1 @@ +export * from '@fuse/components/alert/public-api'; diff --git a/frontend/src/@fuse/components/alert/public-api.ts b/frontend/src/@fuse/components/alert/public-api.ts new file mode 100644 index 00000000..9144d500 --- /dev/null +++ b/frontend/src/@fuse/components/alert/public-api.ts @@ -0,0 +1,3 @@ +export * from '@fuse/components/alert/alert.component'; +export * from '@fuse/components/alert/alert.service'; +export * from '@fuse/components/alert/alert.types'; diff --git a/frontend/src/@fuse/components/card/card.component.html b/frontend/src/@fuse/components/card/card.component.html new file mode 100644 index 00000000..94e8e77a --- /dev/null +++ b/frontend/src/@fuse/components/card/card.component.html @@ -0,0 +1,25 @@ + +@if (flippable) { + +
+ +
+ + +
+ +
+} + + +@if (!flippable) { + + + + + @if (expanded) { +
+ +
+ } +} diff --git a/frontend/src/@fuse/components/card/card.component.scss b/frontend/src/@fuse/components/card/card.component.scss new file mode 100644 index 00000000..7135ac4e --- /dev/null +++ b/frontend/src/@fuse/components/card/card.component.scss @@ -0,0 +1,65 @@ +fuse-card { + position: relative; + display: flex; + overflow: hidden; + @apply bg-card rounded-2xl shadow; + + /* Flippable */ + &.fuse-card-flippable { + border-radius: 0; + overflow: visible; + transform-style: preserve-3d; + transition: transform 1s; + perspective: 600px; + background: transparent; + @apply shadow-none; + + &.fuse-card-face-back { + .fuse-card-front { + visibility: hidden; + opacity: 0; + transform: rotateY(180deg); + } + + .fuse-card-back { + visibility: visible; + opacity: 1; + transform: rotateY(360deg); + } + } + + .fuse-card-front, + .fuse-card-back { + display: flex; + flex-direction: column; + flex: 1 1 auto; + z-index: 10; + transition: + transform 0.5s ease-out 0s, + visibility 0s ease-in 0.2s, + opacity 0s ease-in 0.2s; + backface-visibility: hidden; + @apply bg-card rounded-2xl shadow; + } + + .fuse-card-front { + position: relative; + opacity: 1; + visibility: visible; + transform: rotateY(0deg); + overflow: hidden; + } + + .fuse-card-back { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + opacity: 0; + visibility: hidden; + transform: rotateY(180deg); + overflow: hidden auto; + } + } +} diff --git a/frontend/src/@fuse/components/card/card.component.ts b/frontend/src/@fuse/components/card/card.component.ts new file mode 100644 index 00000000..f1eacce7 --- /dev/null +++ b/frontend/src/@fuse/components/card/card.component.ts @@ -0,0 +1,78 @@ +import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion'; + +import { + Component, + HostBinding, + Input, + OnChanges, + SimpleChanges, + ViewEncapsulation, +} from '@angular/core'; +import { fuseAnimations } from '@fuse/animations'; +import { FuseCardFace } from '@fuse/components/card/card.types'; + +@Component({ + selector: 'fuse-card', + templateUrl: './card.component.html', + styleUrls: ['./card.component.scss'], + encapsulation: ViewEncapsulation.None, + animations: fuseAnimations, + exportAs: 'fuseCard', + standalone: true, + imports: [], +}) +export class FuseCardComponent implements OnChanges { + /* eslint-disable @typescript-eslint/naming-convention */ + static ngAcceptInputType_expanded: BooleanInput; + static ngAcceptInputType_flippable: BooleanInput; + /* eslint-enable @typescript-eslint/naming-convention */ + + @Input() expanded: boolean = false; + @Input() face: FuseCardFace = 'front'; + @Input() flippable: boolean = false; + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Host binding for component classes + */ + @HostBinding('class') get classList(): any { + /* eslint-disable @typescript-eslint/naming-convention */ + return { + 'fuse-card-expanded': this.expanded, + 'fuse-card-face-back': this.flippable && this.face === 'back', + 'fuse-card-face-front': this.flippable && this.face === 'front', + 'fuse-card-flippable': this.flippable, + }; + /* eslint-enable @typescript-eslint/naming-convention */ + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On changes + * + * @param changes + */ + ngOnChanges(changes: SimpleChanges): void { + // Expanded + if ('expanded' in changes) { + // Coerce the value to a boolean + this.expanded = coerceBooleanProperty( + changes.expanded.currentValue + ); + } + + // Flippable + if ('flippable' in changes) { + // Coerce the value to a boolean + this.flippable = coerceBooleanProperty( + changes.flippable.currentValue + ); + } + } +} diff --git a/frontend/src/@fuse/components/card/card.types.ts b/frontend/src/@fuse/components/card/card.types.ts new file mode 100644 index 00000000..72ee87a7 --- /dev/null +++ b/frontend/src/@fuse/components/card/card.types.ts @@ -0,0 +1 @@ +export type FuseCardFace = 'front' | 'back'; diff --git a/frontend/src/@fuse/components/card/index.ts b/frontend/src/@fuse/components/card/index.ts new file mode 100644 index 00000000..ac978a78 --- /dev/null +++ b/frontend/src/@fuse/components/card/index.ts @@ -0,0 +1 @@ +export * from '@fuse/components/card/public-api'; diff --git a/frontend/src/@fuse/components/card/public-api.ts b/frontend/src/@fuse/components/card/public-api.ts new file mode 100644 index 00000000..9d8c31e7 --- /dev/null +++ b/frontend/src/@fuse/components/card/public-api.ts @@ -0,0 +1 @@ +export * from '@fuse/components/card/card.component'; diff --git a/frontend/src/@fuse/components/drawer/drawer.component.html b/frontend/src/@fuse/components/drawer/drawer.component.html new file mode 100644 index 00000000..b3a8acc4 --- /dev/null +++ b/frontend/src/@fuse/components/drawer/drawer.component.html @@ -0,0 +1,3 @@ +
+ +
diff --git a/frontend/src/@fuse/components/drawer/drawer.component.scss b/frontend/src/@fuse/components/drawer/drawer.component.scss new file mode 100644 index 00000000..c6c3f5aa --- /dev/null +++ b/frontend/src/@fuse/components/drawer/drawer.component.scss @@ -0,0 +1,132 @@ +/* Variables */ +:root { + --fuse-drawer-width: 320px; +} + +fuse-drawer { + position: relative; + display: flex; + flex-direction: column; + flex: 1 1 auto; + width: var(--fuse-drawer-width); + min-width: var(--fuse-drawer-width); + max-width: var(--fuse-drawer-width); + z-index: 300; + box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.35); + @apply bg-card; + + /* Animations */ + &.fuse-drawer-animations-enabled { + transition-duration: 400ms; + transition-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1); + transition-property: visibility, margin-left, margin-right, transform, + width, max-width, min-width; + + .fuse-drawer-content { + transition-duration: 400ms; + transition-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1); + transition-property: width, max-width, min-width; + } + } + + /* Over mode */ + &.fuse-drawer-mode-over { + position: absolute; + top: 0; + bottom: 0; + + /* Fixed mode */ + &.fuse-drawer-fixed { + position: fixed; + } + } + + /* Left position */ + &.fuse-drawer-position-left { + /* Side mode */ + &.fuse-drawer-mode-side { + margin-left: calc(var(--fuse-drawer-width) * -1); + + &.fuse-drawer-opened { + margin-left: 0; + } + } + + /* Over mode */ + &.fuse-drawer-mode-over { + left: 0; + transform: translate3d(-100%, 0, 0); + + &.fuse-drawer-opened { + transform: translate3d(0, 0, 0); + } + } + + /* Content */ + .fuse-drawer-content { + left: 0; + } + } + + /* Right position */ + &.fuse-drawer-position-right { + /* Side mode */ + &.fuse-drawer-mode-side { + margin-right: calc(var(--fuse-drawer-width) * -1); + + &.fuse-drawer-opened { + margin-right: 0; + } + } + + /* Over mode */ + &.fuse-drawer-mode-over { + right: 0; + transform: translate3d(100%, 0, 0); + + &.fuse-drawer-opened { + transform: translate3d(0, 0, 0); + } + } + + /* Content */ + .fuse-drawer-content { + right: 0; + } + } + + /* Content */ + .fuse-drawer-content { + position: absolute; + display: flex; + flex: 1 1 auto; + top: 0; + bottom: 0; + width: 100%; + height: 100%; + overflow: hidden; + @apply bg-card; + } +} + +/* Overlay */ +.fuse-drawer-overlay { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: 299; + opacity: 1; + background-color: rgba(0, 0, 0, 0.6); + + /* Fixed mode */ + &.fuse-drawer-overlay-fixed { + position: fixed; + } + + /* Transparent overlay */ + &.fuse-drawer-overlay-transparent { + background-color: transparent; + } +} diff --git a/frontend/src/@fuse/components/drawer/drawer.component.ts b/frontend/src/@fuse/components/drawer/drawer.component.ts new file mode 100644 index 00000000..47fc05ac --- /dev/null +++ b/frontend/src/@fuse/components/drawer/drawer.component.ts @@ -0,0 +1,422 @@ +import { + animate, + AnimationBuilder, + AnimationPlayer, + style, +} from '@angular/animations'; +import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion'; +import { + Component, + ElementRef, + EventEmitter, + HostBinding, + HostListener, + inject, + Input, + OnChanges, + OnDestroy, + OnInit, + Output, + Renderer2, + SimpleChanges, + ViewEncapsulation, +} from '@angular/core'; +import { FuseDrawerService } from '@fuse/components/drawer/drawer.service'; +import { + FuseDrawerMode, + FuseDrawerPosition, +} from '@fuse/components/drawer/drawer.types'; +import { FuseUtilsService } from '@fuse/services/utils/utils.service'; + +@Component({ + selector: 'fuse-drawer', + templateUrl: './drawer.component.html', + styleUrls: ['./drawer.component.scss'], + encapsulation: ViewEncapsulation.None, + exportAs: 'fuseDrawer', + standalone: true, +}) +export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy { + /* eslint-disable @typescript-eslint/naming-convention */ + static ngAcceptInputType_fixed: BooleanInput; + static ngAcceptInputType_opened: BooleanInput; + static ngAcceptInputType_transparentOverlay: BooleanInput; + /* eslint-enable @typescript-eslint/naming-convention */ + + private _animationBuilder = inject(AnimationBuilder); + private _elementRef = inject(ElementRef); + private _renderer2 = inject(Renderer2); + private _fuseDrawerService = inject(FuseDrawerService); + private _fuseUtilsService = inject(FuseUtilsService); + + @Input() fixed: boolean = false; + @Input() mode: FuseDrawerMode = 'side'; + @Input() name: string = this._fuseUtilsService.randomId(); + @Input() opened: boolean = false; + @Input() position: FuseDrawerPosition = 'left'; + @Input() transparentOverlay: boolean = false; + @Output() readonly fixedChanged: EventEmitter = + new EventEmitter(); + @Output() readonly modeChanged: EventEmitter = + new EventEmitter(); + @Output() readonly openedChanged: EventEmitter = + new EventEmitter(); + @Output() readonly positionChanged: EventEmitter = + new EventEmitter(); + + private _animationsEnabled: boolean = false; + private readonly _handleOverlayClick = (): void => this.close(); + private _hovered: boolean = false; + private _overlay: HTMLElement; + private _player: AnimationPlayer; + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Host binding for component classes + */ + @HostBinding('class') get classList(): any { + /* eslint-disable @typescript-eslint/naming-convention */ + return { + 'fuse-drawer-animations-enabled': this._animationsEnabled, + 'fuse-drawer-fixed': this.fixed, + 'fuse-drawer-hover': this._hovered, + [`fuse-drawer-mode-${this.mode}`]: true, + 'fuse-drawer-opened': this.opened, + [`fuse-drawer-position-${this.position}`]: true, + }; + /* eslint-enable @typescript-eslint/naming-convention */ + } + + /** + * Host binding for component inline styles + */ + @HostBinding('style') get styleList(): any { + return { + visibility: this.opened ? 'visible' : 'hidden', + }; + } + + // ----------------------------------------------------------------------------------------------------- + // @ Decorated methods + // ----------------------------------------------------------------------------------------------------- + + /** + * On mouseenter + * + * @private + */ + @HostListener('mouseenter') + private _onMouseenter(): void { + // Enable the animations + this._enableAnimations(); + + // Set the hovered + this._hovered = true; + } + + /** + * On mouseleave + * + * @private + */ + @HostListener('mouseleave') + private _onMouseleave(): void { + // Enable the animations + this._enableAnimations(); + + // Set the hovered + this._hovered = false; + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On changes + * + * @param changes + */ + ngOnChanges(changes: SimpleChanges): void { + // Fixed + if ('fixed' in changes) { + // Coerce the value to a boolean + this.fixed = coerceBooleanProperty(changes.fixed.currentValue); + + // Execute the observable + this.fixedChanged.next(this.fixed); + } + + // Mode + if ('mode' in changes) { + // Get the previous and current values + const previousMode = changes.mode.previousValue; + const currentMode = changes.mode.currentValue; + + // Disable the animations + this._disableAnimations(); + + // If the mode changes: 'over -> side' + if (previousMode === 'over' && currentMode === 'side') { + // Hide the overlay + this._hideOverlay(); + } + + // If the mode changes: 'side -> over' + if (previousMode === 'side' && currentMode === 'over') { + // If the drawer is opened + if (this.opened) { + // Show the overlay + this._showOverlay(); + } + } + + // Execute the observable + this.modeChanged.next(currentMode); + + // Enable the animations after a delay + // The delay must be bigger than the current transition-duration + // to make sure nothing will be animated while the mode is changing + setTimeout(() => { + this._enableAnimations(); + }, 500); + } + + // Opened + if ('opened' in changes) { + // Coerce the value to a boolean + const open = coerceBooleanProperty(changes.opened.currentValue); + + // Open/close the drawer + this._toggleOpened(open); + } + + // Position + if ('position' in changes) { + // Execute the observable + this.positionChanged.next(this.position); + } + + // Transparent overlay + if ('transparentOverlay' in changes) { + // Coerce the value to a boolean + this.transparentOverlay = coerceBooleanProperty( + changes.transparentOverlay.currentValue + ); + } + } + + /** + * On init + */ + ngOnInit(): void { + // Register the drawer + this._fuseDrawerService.registerComponent(this.name, this); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Finish the animation + if (this._player) { + this._player.finish(); + } + + // Deregister the drawer from the registry + this._fuseDrawerService.deregisterComponent(this.name); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Open the drawer + */ + open(): void { + // Return if the drawer has already opened + if (this.opened) { + return; + } + + // Open the drawer + this._toggleOpened(true); + } + + /** + * Close the drawer + */ + close(): void { + // Return if the drawer has already closed + if (!this.opened) { + return; + } + + // Close the drawer + this._toggleOpened(false); + } + + /** + * Toggle the drawer + */ + toggle(): void { + if (this.opened) { + this.close(); + } else { + this.open(); + } + } + + // ----------------------------------------------------------------------------------------------------- + // @ Private methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Enable the animations + * + * @private + */ + private _enableAnimations(): void { + // Return if the animations are already enabled + if (this._animationsEnabled) { + return; + } + + // Enable the animations + this._animationsEnabled = true; + } + + /** + * Disable the animations + * + * @private + */ + private _disableAnimations(): void { + // Return if the animations are already disabled + if (!this._animationsEnabled) { + return; + } + + // Disable the animations + this._animationsEnabled = false; + } + + /** + * Show the backdrop + * + * @private + */ + private _showOverlay(): void { + // Create the backdrop element + this._overlay = this._renderer2.createElement('div'); + + // Add a class to the backdrop element + this._overlay.classList.add('fuse-drawer-overlay'); + + // Add a class depending on the fixed option + if (this.fixed) { + this._overlay.classList.add('fuse-drawer-overlay-fixed'); + } + + // Add a class depending on the transparentOverlay option + if (this.transparentOverlay) { + this._overlay.classList.add('fuse-drawer-overlay-transparent'); + } + + // Append the backdrop to the parent of the drawer + this._renderer2.appendChild( + this._elementRef.nativeElement.parentElement, + this._overlay + ); + + // Create enter animation and attach it to the player + this._player = this._animationBuilder + .build([ + style({ opacity: 0 }), + animate( + '300ms cubic-bezier(0.25, 0.8, 0.25, 1)', + style({ opacity: 1 }) + ), + ]) + .create(this._overlay); + + // Play the animation + this._player.play(); + + // Add an event listener to the overlay + this._overlay.addEventListener('click', this._handleOverlayClick); + } + + /** + * Hide the backdrop + * + * @private + */ + private _hideOverlay(): void { + if (!this._overlay) { + return; + } + + // Create the leave animation and attach it to the player + this._player = this._animationBuilder + .build([ + animate( + '300ms cubic-bezier(0.25, 0.8, 0.25, 1)', + style({ opacity: 0 }) + ), + ]) + .create(this._overlay); + + // Play the animation + this._player.play(); + + // Once the animation is done... + this._player.onDone(() => { + // If the overlay still exists... + if (this._overlay) { + // Remove the event listener + this._overlay.removeEventListener( + 'click', + this._handleOverlayClick + ); + + // Remove the overlay + this._overlay.parentNode.removeChild(this._overlay); + this._overlay = null; + } + }); + } + + /** + * Open/close the drawer + * + * @param open + * @private + */ + private _toggleOpened(open: boolean): void { + // Set the opened + this.opened = open; + + // Enable the animations + this._enableAnimations(); + + // If the mode is 'over' + if (this.mode === 'over') { + // If the drawer opens, show the overlay + if (open) { + this._showOverlay(); + } + // Otherwise, close the overlay + else { + this._hideOverlay(); + } + } + + // Execute the observable + this.openedChanged.next(open); + } +} diff --git a/frontend/src/@fuse/components/drawer/drawer.service.ts b/frontend/src/@fuse/components/drawer/drawer.service.ts new file mode 100644 index 00000000..305d8883 --- /dev/null +++ b/frontend/src/@fuse/components/drawer/drawer.service.ts @@ -0,0 +1,42 @@ +import { Injectable } from '@angular/core'; +import { FuseDrawerComponent } from '@fuse/components/drawer/drawer.component'; + +@Injectable({ providedIn: 'root' }) +export class FuseDrawerService { + private _componentRegistry: Map = new Map< + string, + FuseDrawerComponent + >(); + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Register drawer component + * + * @param name + * @param component + */ + registerComponent(name: string, component: FuseDrawerComponent): void { + this._componentRegistry.set(name, component); + } + + /** + * Deregister drawer component + * + * @param name + */ + deregisterComponent(name: string): void { + this._componentRegistry.delete(name); + } + + /** + * Get drawer component from the registry + * + * @param name + */ + getComponent(name: string): FuseDrawerComponent | undefined { + return this._componentRegistry.get(name); + } +} diff --git a/frontend/src/@fuse/components/drawer/drawer.types.ts b/frontend/src/@fuse/components/drawer/drawer.types.ts new file mode 100644 index 00000000..a51ccb93 --- /dev/null +++ b/frontend/src/@fuse/components/drawer/drawer.types.ts @@ -0,0 +1,3 @@ +export type FuseDrawerMode = 'over' | 'side'; + +export type FuseDrawerPosition = 'left' | 'right'; diff --git a/frontend/src/@fuse/components/drawer/index.ts b/frontend/src/@fuse/components/drawer/index.ts new file mode 100644 index 00000000..3611d47d --- /dev/null +++ b/frontend/src/@fuse/components/drawer/index.ts @@ -0,0 +1 @@ +export * from '@fuse/components/drawer/public-api'; diff --git a/frontend/src/@fuse/components/drawer/public-api.ts b/frontend/src/@fuse/components/drawer/public-api.ts new file mode 100644 index 00000000..306b7d42 --- /dev/null +++ b/frontend/src/@fuse/components/drawer/public-api.ts @@ -0,0 +1,3 @@ +export * from '@fuse/components/drawer/drawer.component'; +export * from '@fuse/components/drawer/drawer.service'; +export * from '@fuse/components/drawer/drawer.types'; diff --git a/frontend/src/@fuse/components/fullscreen/fullscreen.component.html b/frontend/src/@fuse/components/fullscreen/fullscreen.component.html new file mode 100644 index 00000000..5077f63e --- /dev/null +++ b/frontend/src/@fuse/components/fullscreen/fullscreen.component.html @@ -0,0 +1,13 @@ + + + + + + + diff --git a/frontend/src/@fuse/components/fullscreen/fullscreen.component.ts b/frontend/src/@fuse/components/fullscreen/fullscreen.component.ts new file mode 100644 index 00000000..bfffeda5 --- /dev/null +++ b/frontend/src/@fuse/components/fullscreen/fullscreen.component.ts @@ -0,0 +1,59 @@ +import { DOCUMENT, NgTemplateOutlet } from '@angular/common'; +import { + ChangeDetectionStrategy, + Component, + Input, + TemplateRef, + ViewEncapsulation, + inject, +} from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; + +@Component({ + selector: 'fuse-fullscreen', + templateUrl: './fullscreen.component.html', + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + exportAs: 'fuseFullscreen', + standalone: true, + imports: [ + MatButtonModule, + MatTooltipModule, + NgTemplateOutlet, + MatIconModule, + ], +}) +export class FuseFullscreenComponent { + private _document = inject(DOCUMENT); + + @Input() iconTpl: TemplateRef; + @Input() tooltip: string; + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle the fullscreen mode + */ + toggleFullscreen(): void { + if (!this._document.fullscreenEnabled) { + console.log('Fullscreen is not available in this browser.'); + return; + } + + // Check if the fullscreen is already open + const fullScreen = this._document.fullscreenElement; + + // Toggle the fullscreen + if (fullScreen) { + this._document.exitFullscreen(); + } else { + this._document.documentElement.requestFullscreen().catch(() => { + console.error('Entering fullscreen mode failed.'); + }); + } + } +} diff --git a/frontend/src/@fuse/components/fullscreen/index.ts b/frontend/src/@fuse/components/fullscreen/index.ts new file mode 100644 index 00000000..15b41faf --- /dev/null +++ b/frontend/src/@fuse/components/fullscreen/index.ts @@ -0,0 +1 @@ +export * from '@fuse/components/fullscreen/public-api'; diff --git a/frontend/src/@fuse/components/fullscreen/public-api.ts b/frontend/src/@fuse/components/fullscreen/public-api.ts new file mode 100644 index 00000000..3db68687 --- /dev/null +++ b/frontend/src/@fuse/components/fullscreen/public-api.ts @@ -0,0 +1 @@ +export * from '@fuse/components/fullscreen/fullscreen.component'; diff --git a/frontend/src/@fuse/components/highlight/highlight.component.html b/frontend/src/@fuse/components/highlight/highlight.component.html new file mode 100644 index 00000000..b2bf70cd --- /dev/null +++ b/frontend/src/@fuse/components/highlight/highlight.component.html @@ -0,0 +1,8 @@ + + + + +
+
+
+
diff --git a/frontend/src/@fuse/components/highlight/highlight.component.scss b/frontend/src/@fuse/components/highlight/highlight.component.scss new file mode 100644 index 00000000..b433c6ff --- /dev/null +++ b/frontend/src/@fuse/components/highlight/highlight.component.scss @@ -0,0 +1,3 @@ +textarea[fuse-highlight] { + display: none; +} diff --git a/frontend/src/@fuse/components/highlight/highlight.component.ts b/frontend/src/@fuse/components/highlight/highlight.component.ts new file mode 100644 index 00000000..265254b1 --- /dev/null +++ b/frontend/src/@fuse/components/highlight/highlight.component.ts @@ -0,0 +1,135 @@ +import { NgClass } from '@angular/common'; +import { + AfterViewInit, + ChangeDetectionStrategy, + Component, + ElementRef, + EmbeddedViewRef, + inject, + Input, + OnChanges, + SecurityContext, + SimpleChanges, + TemplateRef, + ViewChild, + ViewContainerRef, + ViewEncapsulation, +} from '@angular/core'; +import { DomSanitizer } from '@angular/platform-browser'; +import { FuseHighlightService } from '@fuse/components/highlight/highlight.service'; + +@Component({ + selector: 'textarea[fuse-highlight]', + templateUrl: './highlight.component.html', + styleUrls: ['./highlight.component.scss'], + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + exportAs: 'fuseHighlight', + standalone: true, + imports: [NgClass], +}) +export class FuseHighlightComponent implements OnChanges, AfterViewInit { + private _domSanitizer = inject(DomSanitizer); + private _elementRef = inject(ElementRef); + private _fuseHighlightService = inject(FuseHighlightService); + private _viewContainerRef = inject(ViewContainerRef); + + @Input() code: string; + @Input() lang: string; + @ViewChild(TemplateRef) templateRef: TemplateRef; + + highlightedCode: string; + private _viewRef: EmbeddedViewRef; + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On changes + * + * @param changes + */ + ngOnChanges(changes: SimpleChanges): void { + // Code & Lang + if ('code' in changes || 'lang' in changes) { + // Return if the viewContainerRef is not available + if (!this._viewContainerRef.length) { + return; + } + + // Highlight and insert the code + this._highlightAndInsert(); + } + } + + /** + * After view init + */ + ngAfterViewInit(): void { + // Return if there is no language set + if (!this.lang) { + return; + } + + // If there is no code input, get the code from + // the textarea + if (!this.code) { + // Get the code + this.code = this._elementRef.nativeElement.value; + } + + // Highlight and insert + this._highlightAndInsert(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Private methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Highlight and insert the highlighted code + * + * @private + */ + private _highlightAndInsert(): void { + // Return if the template reference is not available + if (!this.templateRef) { + return; + } + + // Return if the code or language is not defined + if (!this.code || !this.lang) { + return; + } + + // Destroy the component if there is already one + if (this._viewRef) { + this._viewRef.destroy(); + this._viewRef = null; + } + + // Highlight and sanitize the code just in case + this.highlightedCode = this._domSanitizer.sanitize( + SecurityContext.HTML, + this._fuseHighlightService.highlight(this.code, this.lang) + ); + + // Return if the highlighted code is null + if (this.highlightedCode === null) { + return; + } + + // Render and insert the template + this._viewRef = this._viewContainerRef.createEmbeddedView( + this.templateRef, + { + highlightedCode: this.highlightedCode, + lang: this.lang, + } + ); + + // Detect the changes + this._viewRef.detectChanges(); + } +} diff --git a/frontend/src/@fuse/components/highlight/highlight.service.ts b/frontend/src/@fuse/components/highlight/highlight.service.ts new file mode 100644 index 00000000..61b08dc7 --- /dev/null +++ b/frontend/src/@fuse/components/highlight/highlight.service.ts @@ -0,0 +1,67 @@ +import { Injectable } from '@angular/core'; +import hljs from 'highlight.js'; + +@Injectable({ providedIn: 'root' }) +export class FuseHighlightService { + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Highlight + */ + highlight(code: string, language: string): string { + // Format the code + code = this._format(code); + + // Highlight and return the code + return hljs.highlight(code, { language }).value; + } + + // ----------------------------------------------------------------------------------------------------- + // @ Private methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Remove the empty lines around the code block + * and re-align the indentation based on the first + * non-whitespace indented character + * + * @param code + * @private + */ + private _format(code: string): string { + let indentation = 0; + + // Split the code into lines and store the lines + const lines = code.split('\n'); + + // Trim the empty lines around the code block + while (lines.length && lines[0].trim() === '') { + lines.shift(); + } + + while (lines.length && lines[lines.length - 1].trim() === '') { + lines.pop(); + } + + // Iterate through the lines + lines + .filter((line) => line.length) + .forEach((line, index) => { + // Always get the indentation of the first line so we can + // have something to compare with + if (index === 0) { + indentation = line.search(/\S|$/); + return; + } + + // Look at all the remaining lines to figure out the smallest indentation. + indentation = Math.min(line.search(/\S|$/), indentation); + }); + + // Iterate through the lines one more time, remove the extra + // indentation, join them together and return it + return lines.map((line) => line.substring(indentation)).join('\n'); + } +} diff --git a/frontend/src/@fuse/components/highlight/index.ts b/frontend/src/@fuse/components/highlight/index.ts new file mode 100644 index 00000000..46f52e2e --- /dev/null +++ b/frontend/src/@fuse/components/highlight/index.ts @@ -0,0 +1 @@ +export * from '@fuse/components/highlight/public-api'; diff --git a/frontend/src/@fuse/components/highlight/public-api.ts b/frontend/src/@fuse/components/highlight/public-api.ts new file mode 100644 index 00000000..66d766e1 --- /dev/null +++ b/frontend/src/@fuse/components/highlight/public-api.ts @@ -0,0 +1,2 @@ +export * from '@fuse/components/highlight/highlight.component'; +export * from '@fuse/components/highlight/highlight.service'; diff --git a/frontend/src/@fuse/components/loading-bar/index.ts b/frontend/src/@fuse/components/loading-bar/index.ts new file mode 100644 index 00000000..780b263a --- /dev/null +++ b/frontend/src/@fuse/components/loading-bar/index.ts @@ -0,0 +1 @@ +export * from '@fuse/components/loading-bar/public-api'; diff --git a/frontend/src/@fuse/components/loading-bar/loading-bar.component.html b/frontend/src/@fuse/components/loading-bar/loading-bar.component.html new file mode 100644 index 00000000..05003422 --- /dev/null +++ b/frontend/src/@fuse/components/loading-bar/loading-bar.component.html @@ -0,0 +1,3 @@ +@if (show) { + +} diff --git a/frontend/src/@fuse/components/loading-bar/loading-bar.component.scss b/frontend/src/@fuse/components/loading-bar/loading-bar.component.scss new file mode 100644 index 00000000..7a46ec0e --- /dev/null +++ b/frontend/src/@fuse/components/loading-bar/loading-bar.component.scss @@ -0,0 +1,7 @@ +fuse-loading-bar { + position: fixed; + top: 0; + z-index: 999; + width: 100%; + height: 6px; +} diff --git a/frontend/src/@fuse/components/loading-bar/loading-bar.component.ts b/frontend/src/@fuse/components/loading-bar/loading-bar.component.ts new file mode 100644 index 00000000..daaa6ade --- /dev/null +++ b/frontend/src/@fuse/components/loading-bar/loading-bar.component.ts @@ -0,0 +1,86 @@ +import { coerceBooleanProperty } from '@angular/cdk/coercion'; + +import { + Component, + inject, + Input, + OnChanges, + OnDestroy, + OnInit, + SimpleChanges, + ViewEncapsulation, +} from '@angular/core'; +import { MatProgressBarModule } from '@angular/material/progress-bar'; +import { FuseLoadingService } from '@fuse/services/loading'; +import { Subject, takeUntil } from 'rxjs'; + +@Component({ + selector: 'fuse-loading-bar', + templateUrl: './loading-bar.component.html', + styleUrls: ['./loading-bar.component.scss'], + encapsulation: ViewEncapsulation.None, + exportAs: 'fuseLoadingBar', + standalone: true, + imports: [MatProgressBarModule], +}) +export class FuseLoadingBarComponent implements OnChanges, OnInit, OnDestroy { + private _fuseLoadingService = inject(FuseLoadingService); + + @Input() autoMode: boolean = true; + mode: 'determinate' | 'indeterminate'; + progress: number = 0; + show: boolean = false; + private _unsubscribeAll: Subject = new Subject(); + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On changes + * + * @param changes + */ + ngOnChanges(changes: SimpleChanges): void { + // Auto mode + if ('autoMode' in changes) { + // Set the auto mode in the service + this._fuseLoadingService.setAutoMode( + coerceBooleanProperty(changes.autoMode.currentValue) + ); + } + } + + /** + * On init + */ + ngOnInit(): void { + // Subscribe to the service + this._fuseLoadingService.mode$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((value) => { + this.mode = value; + }); + + this._fuseLoadingService.progress$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((value) => { + this.progress = value; + }); + + this._fuseLoadingService.show$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((value) => { + this.show = value; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } +} diff --git a/frontend/src/@fuse/components/loading-bar/public-api.ts b/frontend/src/@fuse/components/loading-bar/public-api.ts new file mode 100644 index 00000000..4a272ee4 --- /dev/null +++ b/frontend/src/@fuse/components/loading-bar/public-api.ts @@ -0,0 +1 @@ +export * from '@fuse/components/loading-bar/loading-bar.component'; diff --git a/frontend/src/@fuse/components/masonry/index.ts b/frontend/src/@fuse/components/masonry/index.ts new file mode 100644 index 00000000..b2f1a036 --- /dev/null +++ b/frontend/src/@fuse/components/masonry/index.ts @@ -0,0 +1 @@ +export * from '@fuse/components/masonry/public-api'; diff --git a/frontend/src/@fuse/components/masonry/masonry.component.html b/frontend/src/@fuse/components/masonry/masonry.component.html new file mode 100644 index 00000000..5bd57310 --- /dev/null +++ b/frontend/src/@fuse/components/masonry/masonry.component.html @@ -0,0 +1,8 @@ +
+ +
diff --git a/frontend/src/@fuse/components/masonry/masonry.component.ts b/frontend/src/@fuse/components/masonry/masonry.component.ts new file mode 100644 index 00000000..cb719e52 --- /dev/null +++ b/frontend/src/@fuse/components/masonry/masonry.component.ts @@ -0,0 +1,83 @@ +import { NgTemplateOutlet } from '@angular/common'; +import { + AfterViewInit, + Component, + Input, + OnChanges, + SimpleChanges, + TemplateRef, + ViewEncapsulation, +} from '@angular/core'; +import { fuseAnimations } from '@fuse/animations'; + +@Component({ + selector: 'fuse-masonry', + templateUrl: './masonry.component.html', + encapsulation: ViewEncapsulation.None, + animations: fuseAnimations, + exportAs: 'fuseMasonry', + standalone: true, + imports: [NgTemplateOutlet], +}) +export class FuseMasonryComponent implements OnChanges, AfterViewInit { + @Input() columnsTemplate: TemplateRef; + @Input() columns: number; + @Input() items: any[] = []; + distributedColumns: any[] = []; + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On changes + * + * @param changes + */ + ngOnChanges(changes: SimpleChanges): void { + // Columns + if ('columns' in changes) { + // Distribute the items + this._distributeItems(); + } + + // Items + if ('items' in changes) { + // Distribute the items + this._distributeItems(); + } + } + + /** + * After view init + */ + ngAfterViewInit(): void { + // Distribute the items for the first time + this._distributeItems(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Private methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Distribute items into columns + */ + private _distributeItems(): void { + // Return an empty array if there are no items + if (this.items.length === 0) { + this.distributedColumns = []; + return; + } + + // Prepare the distributed columns array + this.distributedColumns = Array.from(Array(this.columns), (item) => ({ + items: [], + })); + + // Distribute the items to columns + for (let i = 0; i < this.items.length; i++) { + this.distributedColumns[i % this.columns].items.push(this.items[i]); + } + } +} diff --git a/frontend/src/@fuse/components/masonry/public-api.ts b/frontend/src/@fuse/components/masonry/public-api.ts new file mode 100644 index 00000000..ea222316 --- /dev/null +++ b/frontend/src/@fuse/components/masonry/public-api.ts @@ -0,0 +1 @@ +export * from '@fuse/components/masonry/masonry.component'; diff --git a/frontend/src/@fuse/components/navigation/horizontal/components/basic/basic.component.html b/frontend/src/@fuse/components/navigation/horizontal/components/basic/basic.component.html new file mode 100644 index 00000000..6dd4dd9c --- /dev/null +++ b/frontend/src/@fuse/components/navigation/horizontal/components/basic/basic.component.html @@ -0,0 +1,149 @@ + +
+ + @if (item.link && !item.externalLink && !item.function && !item.disabled) { +
+ +
+ } + + + @if (item.link && item.externalLink && !item.function && !item.disabled) { + + + + } + + + @if (!item.link && item.function && !item.disabled) { +
+ +
+ } + + + @if (item.link && !item.externalLink && item.function && !item.disabled) { +
+ +
+ } + + + @if (item.link && item.externalLink && item.function && !item.disabled) { + + + + } + + + @if (!item.link && !item.function && !item.disabled) { +
+ +
+ } + + + @if (item.disabled) { +
+ +
+ } +
+ + + + + @if (item.icon) { + + } + + +
+
+ + {{ item.title }} + +
+ @if (item.subtitle) { +
+ + {{ item.subtitle }} + +
+ } +
+ + + @if (item.badge) { +
+
+ {{ item.badge.title }} +
+
+ } +
diff --git a/frontend/src/@fuse/components/navigation/horizontal/components/basic/basic.component.ts b/frontend/src/@fuse/components/navigation/horizontal/components/basic/basic.component.ts new file mode 100644 index 00000000..060946cd --- /dev/null +++ b/frontend/src/@fuse/components/navigation/horizontal/components/basic/basic.component.ts @@ -0,0 +1,100 @@ +import { NgClass, NgTemplateOutlet } from '@angular/common'; +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + Input, + OnDestroy, + OnInit, + inject, +} from '@angular/core'; +import { MatIconModule } from '@angular/material/icon'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { + IsActiveMatchOptions, + RouterLink, + RouterLinkActive, +} from '@angular/router'; +import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component'; +import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; +import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; +import { FuseUtilsService } from '@fuse/services/utils/utils.service'; +import { Subject, takeUntil } from 'rxjs'; + +@Component({ + selector: 'fuse-horizontal-navigation-basic-item', + templateUrl: './basic.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [ + NgClass, + RouterLink, + RouterLinkActive, + MatTooltipModule, + NgTemplateOutlet, + MatMenuModule, + MatIconModule, + ], +}) +export class FuseHorizontalNavigationBasicItemComponent + implements OnInit, OnDestroy +{ + private _changeDetectorRef = inject(ChangeDetectorRef); + private _fuseNavigationService = inject(FuseNavigationService); + private _fuseUtilsService = inject(FuseUtilsService); + + @Input() item: FuseNavigationItem; + @Input() name: string; + + // Set the equivalent of {exact: false} as default for active match options. + // We are not assigning the item.isActiveMatchOptions directly to the + // [routerLinkActiveOptions] because if it's "undefined" initially, the router + // will throw an error and stop working. + isActiveMatchOptions: IsActiveMatchOptions = + this._fuseUtilsService.subsetMatchOptions; + + private _fuseHorizontalNavigationComponent: FuseHorizontalNavigationComponent; + private _unsubscribeAll: Subject = new Subject(); + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Set the "isActiveMatchOptions" either from item's + // "isActiveMatchOptions" or the equivalent form of + // item's "exactMatch" option + this.isActiveMatchOptions = + this.item.isActiveMatchOptions ?? this.item.exactMatch + ? this._fuseUtilsService.exactMatchOptions + : this._fuseUtilsService.subsetMatchOptions; + + // Get the parent navigation component + this._fuseHorizontalNavigationComponent = + this._fuseNavigationService.getComponent(this.name); + + // Mark for check + this._changeDetectorRef.markForCheck(); + + // Subscribe to onRefreshed on the navigation component + this._fuseHorizontalNavigationComponent.onRefreshed + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } +} diff --git a/frontend/src/@fuse/components/navigation/horizontal/components/branch/branch.component.html b/frontend/src/@fuse/components/navigation/horizontal/components/branch/branch.component.html new file mode 100644 index 00000000..76475d31 --- /dev/null +++ b/frontend/src/@fuse/components/navigation/horizontal/components/branch/branch.component.html @@ -0,0 +1,135 @@ +@if (!child) { +
+ +
+} + + + @for (item of item.children; track trackByFn($index, item)) { + + @if ((item.hidden && !item.hidden(item)) || !item.hidden) { + + @if (item.type === 'basic') { +
+ +
+ } + + + @if ( + item.type === 'aside' || + item.type === 'collapsable' || + item.type === 'group' + ) { +
+ + +
+ } + + + @if (item.type === 'divider') { +
+ +
+ } + } + } +
+ + + +
+
+ + @if (item.icon) { + + } + + +
+
+ + {{ item.title }} + +
+ @if (item.subtitle) { +
+ + {{ item.subtitle }} + +
+ } +
+ + + @if (item.badge) { +
+
+ {{ item.badge.title }} +
+
+ } +
+
+
diff --git a/frontend/src/@fuse/components/navigation/horizontal/components/branch/branch.component.ts b/frontend/src/@fuse/components/navigation/horizontal/components/branch/branch.component.ts new file mode 100644 index 00000000..a474a4a5 --- /dev/null +++ b/frontend/src/@fuse/components/navigation/horizontal/components/branch/branch.component.ts @@ -0,0 +1,109 @@ +import { BooleanInput } from '@angular/cdk/coercion'; +import { NgClass, NgTemplateOutlet } from '@angular/common'; +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + Input, + OnDestroy, + OnInit, + ViewChild, + forwardRef, + inject, +} from '@angular/core'; +import { MatIconModule } from '@angular/material/icon'; +import { MatMenu, MatMenuModule } from '@angular/material/menu'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { FuseHorizontalNavigationBasicItemComponent } from '@fuse/components/navigation/horizontal/components/basic/basic.component'; +import { FuseHorizontalNavigationDividerItemComponent } from '@fuse/components/navigation/horizontal/components/divider/divider.component'; +import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component'; +import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; +import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; +import { Subject, takeUntil } from 'rxjs'; + +@Component({ + selector: 'fuse-horizontal-navigation-branch-item', + templateUrl: './branch.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [ + NgClass, + MatMenuModule, + NgTemplateOutlet, + FuseHorizontalNavigationBasicItemComponent, + forwardRef(() => FuseHorizontalNavigationBranchItemComponent), + FuseHorizontalNavigationDividerItemComponent, + MatTooltipModule, + MatIconModule, + ], +}) +export class FuseHorizontalNavigationBranchItemComponent + implements OnInit, OnDestroy +{ + /* eslint-disable @typescript-eslint/naming-convention */ + static ngAcceptInputType_child: BooleanInput; + /* eslint-enable @typescript-eslint/naming-convention */ + + private _changeDetectorRef = inject(ChangeDetectorRef); + private _fuseNavigationService = inject(FuseNavigationService); + + @Input() child: boolean = false; + @Input() item: FuseNavigationItem; + @Input() name: string; + @ViewChild('matMenu', { static: true }) matMenu: MatMenu; + + private _fuseHorizontalNavigationComponent: FuseHorizontalNavigationComponent; + private _unsubscribeAll: Subject = new Subject(); + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Get the parent navigation component + this._fuseHorizontalNavigationComponent = + this._fuseNavigationService.getComponent(this.name); + + // Subscribe to onRefreshed on the navigation component + this._fuseHorizontalNavigationComponent.onRefreshed + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Trigger the change detection + */ + triggerChangeDetection(): void { + // Mark for check + this._changeDetectorRef.markForCheck(); + } + + /** + * Track by function for ngFor loops + * + * @param index + * @param item + */ + trackByFn(index: number, item: any): any { + return item.id || index; + } +} diff --git a/frontend/src/@fuse/components/navigation/horizontal/components/divider/divider.component.html b/frontend/src/@fuse/components/navigation/horizontal/components/divider/divider.component.html new file mode 100644 index 00000000..7b578dd2 --- /dev/null +++ b/frontend/src/@fuse/components/navigation/horizontal/components/divider/divider.component.html @@ -0,0 +1,5 @@ + +
diff --git a/frontend/src/@fuse/components/navigation/horizontal/components/divider/divider.component.ts b/frontend/src/@fuse/components/navigation/horizontal/components/divider/divider.component.ts new file mode 100644 index 00000000..d1e3a1c0 --- /dev/null +++ b/frontend/src/@fuse/components/navigation/horizontal/components/divider/divider.component.ts @@ -0,0 +1,64 @@ +import { NgClass } from '@angular/common'; +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + inject, + Input, + OnDestroy, + OnInit, +} from '@angular/core'; +import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component'; +import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; +import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; +import { Subject, takeUntil } from 'rxjs'; + +@Component({ + selector: 'fuse-horizontal-navigation-divider-item', + templateUrl: './divider.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [NgClass], +}) +export class FuseHorizontalNavigationDividerItemComponent + implements OnInit, OnDestroy +{ + private _changeDetectorRef = inject(ChangeDetectorRef); + private _fuseNavigationService = inject(FuseNavigationService); + + @Input() item: FuseNavigationItem; + @Input() name: string; + + private _fuseHorizontalNavigationComponent: FuseHorizontalNavigationComponent; + private _unsubscribeAll: Subject = new Subject(); + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Get the parent navigation component + this._fuseHorizontalNavigationComponent = + this._fuseNavigationService.getComponent(this.name); + + // Subscribe to onRefreshed on the navigation component + this._fuseHorizontalNavigationComponent.onRefreshed + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } +} diff --git a/frontend/src/@fuse/components/navigation/horizontal/components/spacer/spacer.component.html b/frontend/src/@fuse/components/navigation/horizontal/components/spacer/spacer.component.html new file mode 100644 index 00000000..89df61a5 --- /dev/null +++ b/frontend/src/@fuse/components/navigation/horizontal/components/spacer/spacer.component.html @@ -0,0 +1,5 @@ + +
diff --git a/frontend/src/@fuse/components/navigation/horizontal/components/spacer/spacer.component.ts b/frontend/src/@fuse/components/navigation/horizontal/components/spacer/spacer.component.ts new file mode 100644 index 00000000..12d77593 --- /dev/null +++ b/frontend/src/@fuse/components/navigation/horizontal/components/spacer/spacer.component.ts @@ -0,0 +1,64 @@ +import { NgClass } from '@angular/common'; +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + inject, + Input, + OnDestroy, + OnInit, +} from '@angular/core'; +import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component'; +import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; +import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; +import { Subject, takeUntil } from 'rxjs'; + +@Component({ + selector: 'fuse-horizontal-navigation-spacer-item', + templateUrl: './spacer.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [NgClass], +}) +export class FuseHorizontalNavigationSpacerItemComponent + implements OnInit, OnDestroy +{ + private _changeDetectorRef = inject(ChangeDetectorRef); + private _fuseNavigationService = inject(FuseNavigationService); + + @Input() item: FuseNavigationItem; + @Input() name: string; + + private _fuseHorizontalNavigationComponent: FuseHorizontalNavigationComponent; + private _unsubscribeAll: Subject = new Subject(); + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Get the parent navigation component + this._fuseHorizontalNavigationComponent = + this._fuseNavigationService.getComponent(this.name); + + // Subscribe to onRefreshed on the navigation component + this._fuseHorizontalNavigationComponent.onRefreshed + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } +} diff --git a/frontend/src/@fuse/components/navigation/horizontal/horizontal.component.html b/frontend/src/@fuse/components/navigation/horizontal/horizontal.component.html new file mode 100644 index 00000000..1c193f38 --- /dev/null +++ b/frontend/src/@fuse/components/navigation/horizontal/horizontal.component.html @@ -0,0 +1,37 @@ +
+ @for (item of navigation; track trackByFn($index, item)) { + + @if ((item.hidden && !item.hidden(item)) || !item.hidden) { + + @if (item.type === 'basic') { + + } + + + @if ( + item.type === 'aside' || + item.type === 'collapsable' || + item.type === 'group' + ) { + + } + + + @if (item.type === 'spacer') { + + } + } + } +
diff --git a/frontend/src/@fuse/components/navigation/horizontal/horizontal.component.scss b/frontend/src/@fuse/components/navigation/horizontal/horizontal.component.scss new file mode 100644 index 00000000..d08bfecc --- /dev/null +++ b/frontend/src/@fuse/components/navigation/horizontal/horizontal.component.scss @@ -0,0 +1,166 @@ +/* Root navigation specific */ +fuse-horizontal-navigation { + .fuse-horizontal-navigation-wrapper { + display: flex; + align-items: center; + + /* Basic, Branch */ + fuse-horizontal-navigation-basic-item, + fuse-horizontal-navigation-branch-item { + @screen sm { + &:hover { + .fuse-horizontal-navigation-item-wrapper { + @apply bg-hover; + } + } + } + + .fuse-horizontal-navigation-item-wrapper { + border-radius: 4px; + overflow: hidden; + + .fuse-horizontal-navigation-item { + padding: 0 16px; + cursor: pointer; + user-select: none; + + .fuse-horizontal-navigation-item-icon { + margin-right: 12px; + } + } + } + } + + /* Basic - When item active (current link) */ + fuse-horizontal-navigation-basic-item { + .fuse-horizontal-navigation-item-active, + .fuse-horizontal-navigation-item-active-forced { + .fuse-horizontal-navigation-item-title { + @apply text-primary #{'!important'}; + } + + .fuse-horizontal-navigation-item-subtitle { + @apply text-primary-400 #{'!important'}; + + .dark & { + @apply text-primary-600 #{'!important'}; + } + } + + .fuse-horizontal-navigation-item-icon { + @apply text-primary #{'!important'}; + } + } + } + + /* Branch - When menu open */ + fuse-horizontal-navigation-branch-item { + .fuse-horizontal-navigation-menu-active, + .fuse-horizontal-navigation-menu-active-forced { + .fuse-horizontal-navigation-item-wrapper { + @apply bg-hover; + } + } + } + + /* Spacer */ + fuse-horizontal-navigation-spacer-item { + margin: 12px 0; + } + } +} + +/* Menu panel specific */ +.fuse-horizontal-navigation-menu-panel { + .fuse-horizontal-navigation-menu-item { + height: auto; + min-height: 0; + line-height: normal; + white-space: normal; + + /* Basic, Branch */ + fuse-horizontal-navigation-basic-item, + fuse-horizontal-navigation-branch-item, + fuse-horizontal-navigation-divider-item { + display: flex; + flex: 1 1 auto; + } + + /* Divider */ + fuse-horizontal-navigation-divider-item { + margin: 8px -16px; + + .fuse-horizontal-navigation-item-wrapper { + height: 1px; + box-shadow: 0 1px 0 0; + } + } + } +} + +/* Navigation menu item common */ +.fuse-horizontal-navigation-menu-item { + /* Basic - When item active (current link) */ + fuse-horizontal-navigation-basic-item { + .fuse-horizontal-navigation-item-active, + .fuse-horizontal-navigation-item-active-forced { + .fuse-horizontal-navigation-item-title { + @apply text-primary #{'!important'}; + } + + .fuse-horizontal-navigation-item-subtitle { + @apply text-primary-400 #{'!important'}; + + .dark & { + @apply text-primary-600 #{'!important'}; + } + } + + .fuse-horizontal-navigation-item-icon { + @apply text-primary #{'!important'}; + } + } + } + + .fuse-horizontal-navigation-item-wrapper { + width: 100%; + + &.fuse-horizontal-navigation-item-has-subtitle { + .fuse-horizontal-navigation-item { + min-height: 56px; + } + } + + .fuse-horizontal-navigation-item { + position: relative; + display: flex; + align-items: center; + justify-content: flex-start; + min-height: 48px; + width: 100%; + font-size: 13px; + font-weight: 500; + text-decoration: none; + + .fuse-horizontal-navigation-item-title-wrapper { + .fuse-horizontal-navigation-item-subtitle { + font-size: 12px; + } + } + + .fuse-horizontal-navigation-item-badge { + margin-left: auto; + + .fuse-horizontal-navigation-item-badge-content { + display: flex; + align-items: center; + justify-content: center; + font-size: 10px; + font-weight: 600; + white-space: nowrap; + height: 20px; + } + } + } + } +} diff --git a/frontend/src/@fuse/components/navigation/horizontal/horizontal.component.ts b/frontend/src/@fuse/components/navigation/horizontal/horizontal.component.ts new file mode 100644 index 00000000..6c03011f --- /dev/null +++ b/frontend/src/@fuse/components/navigation/horizontal/horizontal.component.ts @@ -0,0 +1,116 @@ +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + Input, + OnChanges, + OnDestroy, + OnInit, + SimpleChanges, + ViewEncapsulation, + inject, +} from '@angular/core'; +import { fuseAnimations } from '@fuse/animations'; +import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; +import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; +import { FuseUtilsService } from '@fuse/services/utils/utils.service'; +import { ReplaySubject, Subject } from 'rxjs'; +import { FuseHorizontalNavigationBasicItemComponent } from './components/basic/basic.component'; +import { FuseHorizontalNavigationBranchItemComponent } from './components/branch/branch.component'; +import { FuseHorizontalNavigationSpacerItemComponent } from './components/spacer/spacer.component'; + +@Component({ + selector: 'fuse-horizontal-navigation', + templateUrl: './horizontal.component.html', + styleUrls: ['./horizontal.component.scss'], + animations: fuseAnimations, + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + exportAs: 'fuseHorizontalNavigation', + standalone: true, + imports: [ + FuseHorizontalNavigationBasicItemComponent, + FuseHorizontalNavigationBranchItemComponent, + FuseHorizontalNavigationSpacerItemComponent, + ], +}) +export class FuseHorizontalNavigationComponent + implements OnChanges, OnInit, OnDestroy +{ + private _changeDetectorRef = inject(ChangeDetectorRef); + private _fuseNavigationService = inject(FuseNavigationService); + private _fuseUtilsService = inject(FuseUtilsService); + + @Input() name: string = this._fuseUtilsService.randomId(); + @Input() navigation: FuseNavigationItem[]; + + onRefreshed: ReplaySubject = new ReplaySubject(1); + private _unsubscribeAll: Subject = new Subject(); + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On changes + * + * @param changes + */ + ngOnChanges(changes: SimpleChanges): void { + // Navigation + if ('navigation' in changes) { + // Mark for check + this._changeDetectorRef.markForCheck(); + } + } + + /** + * On init + */ + ngOnInit(): void { + // Make sure the name input is not an empty string + if (this.name === '') { + this.name = this._fuseUtilsService.randomId(); + } + + // Register the navigation component + this._fuseNavigationService.registerComponent(this.name, this); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Deregister the navigation component from the registry + this._fuseNavigationService.deregisterComponent(this.name); + + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Refresh the component to apply the changes + */ + refresh(): void { + // Mark for check + this._changeDetectorRef.markForCheck(); + + // Execute the observable + this.onRefreshed.next(true); + } + + /** + * Track by function for ngFor loops + * + * @param index + * @param item + */ + trackByFn(index: number, item: any): any { + return item.id || index; + } +} diff --git a/frontend/src/@fuse/components/navigation/index.ts b/frontend/src/@fuse/components/navigation/index.ts new file mode 100644 index 00000000..2598d801 --- /dev/null +++ b/frontend/src/@fuse/components/navigation/index.ts @@ -0,0 +1 @@ +export * from '@fuse/components/navigation/public-api'; diff --git a/frontend/src/@fuse/components/navigation/navigation.service.ts b/frontend/src/@fuse/components/navigation/navigation.service.ts new file mode 100644 index 00000000..5aa9298a --- /dev/null +++ b/frontend/src/@fuse/components/navigation/navigation.service.ts @@ -0,0 +1,169 @@ +import { Injectable } from '@angular/core'; +import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; + +@Injectable({ providedIn: 'root' }) +export class FuseNavigationService { + private _componentRegistry: Map = new Map(); + private _navigationStore: Map = new Map< + string, + any + >(); + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Register navigation component + * + * @param name + * @param component + */ + registerComponent(name: string, component: any): void { + this._componentRegistry.set(name, component); + } + + /** + * Deregister navigation component + * + * @param name + */ + deregisterComponent(name: string): void { + this._componentRegistry.delete(name); + } + + /** + * Get navigation component from the registry + * + * @param name + */ + getComponent(name: string): T { + return this._componentRegistry.get(name); + } + + /** + * Store the given navigation with the given key + * + * @param key + * @param navigation + */ + storeNavigation(key: string, navigation: FuseNavigationItem[]): void { + // Add to the store + this._navigationStore.set(key, navigation); + } + + /** + * Get navigation from storage by key + * + * @param key + */ + getNavigation(key: string): FuseNavigationItem[] { + return this._navigationStore.get(key) ?? []; + } + + /** + * Delete the navigation from the storage + * + * @param key + */ + deleteNavigation(key: string): void { + // Check if the navigation exists + if (!this._navigationStore.has(key)) { + console.warn( + `Navigation with the key '${key}' does not exist in the store.` + ); + } + + // Delete from the storage + this._navigationStore.delete(key); + } + + /** + * Utility function that returns a flattened + * version of the given navigation array + * + * @param navigation + * @param flatNavigation + */ + getFlatNavigation( + navigation: FuseNavigationItem[], + flatNavigation: FuseNavigationItem[] = [] + ): FuseNavigationItem[] { + for (const item of navigation) { + if (item.type === 'basic') { + flatNavigation.push(item); + continue; + } + + if ( + item.type === 'aside' || + item.type === 'collapsable' || + item.type === 'group' + ) { + if (item.children) { + this.getFlatNavigation(item.children, flatNavigation); + } + } + } + + return flatNavigation; + } + + /** + * Utility function that returns the item + * with the given id from given navigation + * + * @param id + * @param navigation + */ + getItem( + id: string, + navigation: FuseNavigationItem[] + ): FuseNavigationItem | null { + for (const item of navigation) { + if (item.id === id) { + return item; + } + + if (item.children) { + const childItem = this.getItem(id, item.children); + + if (childItem) { + return childItem; + } + } + } + + return null; + } + + /** + * Utility function that returns the item's parent + * with the given id from given navigation + * + * @param id + * @param navigation + * @param parent + */ + getItemParent( + id: string, + navigation: FuseNavigationItem[], + parent: FuseNavigationItem[] | FuseNavigationItem + ): FuseNavigationItem[] | FuseNavigationItem | null { + for (const item of navigation) { + if (item.id === id) { + return parent; + } + + if (item.children) { + const childItem = this.getItemParent(id, item.children, item); + + if (childItem) { + return childItem; + } + } + } + + return null; + } +} diff --git a/frontend/src/@fuse/components/navigation/navigation.types.ts b/frontend/src/@fuse/components/navigation/navigation.types.ts new file mode 100644 index 00000000..aa6491ea --- /dev/null +++ b/frontend/src/@fuse/components/navigation/navigation.types.ts @@ -0,0 +1,49 @@ +import { + IsActiveMatchOptions, + Params, + QueryParamsHandling, +} from '@angular/router'; + +export interface FuseNavigationItem { + id?: string; + title?: string; + subtitle?: string; + type: 'aside' | 'basic' | 'collapsable' | 'divider' | 'group' | 'spacer'; + hidden?: (item: FuseNavigationItem) => boolean; + active?: boolean; + disabled?: boolean; + tooltip?: string; + link?: string; + fragment?: string; + preserveFragment?: boolean; + queryParams?: Params | null; + queryParamsHandling?: QueryParamsHandling | null; + externalLink?: boolean; + target?: '_blank' | '_self' | '_parent' | '_top' | string; + exactMatch?: boolean; + isActiveMatchOptions?: IsActiveMatchOptions; + function?: (item: FuseNavigationItem) => void; + classes?: { + title?: string; + subtitle?: string; + icon?: string; + wrapper?: string; + }; + icon?: string; + badge?: { + title?: string; + classes?: string; + }; + children?: FuseNavigationItem[]; + meta?: any; +} + +export type FuseVerticalNavigationAppearance = + | 'default' + | 'compact' + | 'dense' + | 'thin'; + +export type FuseVerticalNavigationMode = 'over' | 'side'; + +export type FuseVerticalNavigationPosition = 'left' | 'right'; diff --git a/frontend/src/@fuse/components/navigation/public-api.ts b/frontend/src/@fuse/components/navigation/public-api.ts new file mode 100644 index 00000000..c68a2d7a --- /dev/null +++ b/frontend/src/@fuse/components/navigation/public-api.ts @@ -0,0 +1,4 @@ +export * from '@fuse/components/navigation/horizontal/horizontal.component'; +export * from '@fuse/components/navigation/navigation.service'; +export * from '@fuse/components/navigation/navigation.types'; +export * from '@fuse/components/navigation/vertical/vertical.component'; diff --git a/frontend/src/@fuse/components/navigation/vertical/components/aside/aside.component.html b/frontend/src/@fuse/components/navigation/vertical/components/aside/aside.component.html new file mode 100644 index 00000000..d6189342 --- /dev/null +++ b/frontend/src/@fuse/components/navigation/vertical/components/aside/aside.component.html @@ -0,0 +1,102 @@ +
+
+ + @if (item.icon) { + + } + + +
+
+ + {{ item.title }} + +
+ @if (item.subtitle) { +
+ + {{ item.subtitle }} + +
+ } +
+ + + @if (item.badge) { +
+
+ {{ item.badge.title }} +
+
+ } +
+
+ +@if (!skipChildren) { +
+ @for (item of item.children; track trackByFn($index, item)) { + + @if ((item.hidden && !item.hidden(item)) || !item.hidden) { + + @if (item.type === 'basic') { + + } + + + @if (item.type === 'collapsable') { + + } + + + @if (item.type === 'divider') { + + } + + + @if (item.type === 'group') { + + } + + + @if (item.type === 'spacer') { + + } + } + } +
+} diff --git a/frontend/src/@fuse/components/navigation/vertical/components/aside/aside.component.ts b/frontend/src/@fuse/components/navigation/vertical/components/aside/aside.component.ts new file mode 100644 index 00000000..c11efb6e --- /dev/null +++ b/frontend/src/@fuse/components/navigation/vertical/components/aside/aside.component.ts @@ -0,0 +1,203 @@ +import { BooleanInput } from '@angular/cdk/coercion'; +import { NgClass } from '@angular/common'; +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + Input, + OnChanges, + OnDestroy, + OnInit, + SimpleChanges, + inject, +} from '@angular/core'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { NavigationEnd, Router } from '@angular/router'; +import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; +import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; +import { FuseVerticalNavigationBasicItemComponent } from '@fuse/components/navigation/vertical/components/basic/basic.component'; +import { FuseVerticalNavigationCollapsableItemComponent } from '@fuse/components/navigation/vertical/components/collapsable/collapsable.component'; +import { FuseVerticalNavigationDividerItemComponent } from '@fuse/components/navigation/vertical/components/divider/divider.component'; +import { FuseVerticalNavigationGroupItemComponent } from '@fuse/components/navigation/vertical/components/group/group.component'; +import { FuseVerticalNavigationSpacerItemComponent } from '@fuse/components/navigation/vertical/components/spacer/spacer.component'; +import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component'; +import { Subject, filter, takeUntil } from 'rxjs'; + +@Component({ + selector: 'fuse-vertical-navigation-aside-item', + templateUrl: './aside.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [ + NgClass, + MatTooltipModule, + MatIconModule, + FuseVerticalNavigationBasicItemComponent, + FuseVerticalNavigationCollapsableItemComponent, + FuseVerticalNavigationDividerItemComponent, + FuseVerticalNavigationGroupItemComponent, + FuseVerticalNavigationSpacerItemComponent, + ], +}) +export class FuseVerticalNavigationAsideItemComponent + implements OnChanges, OnInit, OnDestroy +{ + /* eslint-disable @typescript-eslint/naming-convention */ + static ngAcceptInputType_autoCollapse: BooleanInput; + static ngAcceptInputType_skipChildren: BooleanInput; + /* eslint-enable @typescript-eslint/naming-convention */ + + private _changeDetectorRef = inject(ChangeDetectorRef); + private _router = inject(Router); + private _fuseNavigationService = inject(FuseNavigationService); + + @Input() activeItemId: string; + @Input() autoCollapse: boolean; + @Input() item: FuseNavigationItem; + @Input() name: string; + @Input() skipChildren: boolean; + + active: boolean = false; + private _fuseVerticalNavigationComponent: FuseVerticalNavigationComponent; + private _unsubscribeAll: Subject = new Subject(); + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On changes + * + * @param changes + */ + ngOnChanges(changes: SimpleChanges): void { + // Active item id + if ('activeItemId' in changes) { + // Mark if active + this._markIfActive(this._router.url); + } + } + + /** + * On init + */ + ngOnInit(): void { + // Mark if active + this._markIfActive(this._router.url); + + // Attach a listener to the NavigationEnd event + this._router.events + .pipe( + filter( + (event): event is NavigationEnd => + event instanceof NavigationEnd + ), + takeUntil(this._unsubscribeAll) + ) + .subscribe((event: NavigationEnd) => { + // Mark if active + this._markIfActive(event.urlAfterRedirects); + }); + + // Get the parent navigation component + this._fuseVerticalNavigationComponent = + this._fuseNavigationService.getComponent(this.name); + + // Subscribe to onRefreshed on the navigation component + this._fuseVerticalNavigationComponent.onRefreshed + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Track by function for ngFor loops + * + * @param index + * @param item + */ + trackByFn(index: number, item: any): any { + return item.id || index; + } + + // ----------------------------------------------------------------------------------------------------- + // @ Private methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Check if the given item has the given url + * in one of its children + * + * @param item + * @param currentUrl + * @private + */ + private _hasActiveChild( + item: FuseNavigationItem, + currentUrl: string + ): boolean { + const children = item.children; + + if (!children) { + return false; + } + + for (const child of children) { + if (child.children) { + if (this._hasActiveChild(child, currentUrl)) { + return true; + } + } + + // Skip items other than 'basic' + if (child.type !== 'basic') { + continue; + } + + // Check if the child has a link and is active + if ( + child.link && + this._router.isActive(child.link, child.exactMatch || false) + ) { + return true; + } + } + + return false; + } + + /** + * Decide and mark if the item is active + * + * @private + */ + private _markIfActive(currentUrl: string): void { + // Check if the activeItemId is equals to this item id + this.active = this.activeItemId === this.item.id; + + // If the aside has a children that is active, + // always mark it as active + if (this._hasActiveChild(this.item, currentUrl)) { + this.active = true; + } + + // Mark for check + this._changeDetectorRef.markForCheck(); + } +} diff --git a/frontend/src/@fuse/components/navigation/vertical/components/basic/basic.component.html b/frontend/src/@fuse/components/navigation/vertical/components/basic/basic.component.html new file mode 100644 index 00000000..f10bac11 --- /dev/null +++ b/frontend/src/@fuse/components/navigation/vertical/components/basic/basic.component.html @@ -0,0 +1,149 @@ + +
+ + @if (item.link && !item.externalLink && !item.function && !item.disabled) { + + + + } + + + @if (item.link && item.externalLink && !item.function && !item.disabled) { + + + + } + + + @if (!item.link && item.function && !item.disabled) { +
+ +
+ } + + + @if (item.link && !item.externalLink && item.function && !item.disabled) { + + + + } + + + @if (item.link && item.externalLink && item.function && !item.disabled) { + + + + } + + + @if (!item.link && !item.function && !item.disabled) { +
+ +
+ } + + + @if (item.disabled) { +
+ +
+ } +
+ + + + + @if (item.icon) { + + } + + +
+
+ + {{ item.title }} + +
+ @if (item.subtitle) { +
+ + {{ item.subtitle }} + +
+ } +
+ + + @if (item.badge) { +
+
+ {{ item.badge.title }} +
+
+ } +
diff --git a/frontend/src/@fuse/components/navigation/vertical/components/basic/basic.component.ts b/frontend/src/@fuse/components/navigation/vertical/components/basic/basic.component.ts new file mode 100644 index 00000000..182018d5 --- /dev/null +++ b/frontend/src/@fuse/components/navigation/vertical/components/basic/basic.component.ts @@ -0,0 +1,98 @@ +import { NgClass, NgTemplateOutlet } from '@angular/common'; +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + Input, + OnDestroy, + OnInit, + inject, +} from '@angular/core'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { + IsActiveMatchOptions, + RouterLink, + RouterLinkActive, +} from '@angular/router'; +import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; +import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; +import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component'; +import { FuseUtilsService } from '@fuse/services/utils/utils.service'; +import { Subject, takeUntil } from 'rxjs'; + +@Component({ + selector: 'fuse-vertical-navigation-basic-item', + templateUrl: './basic.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [ + NgClass, + RouterLink, + RouterLinkActive, + MatTooltipModule, + NgTemplateOutlet, + MatIconModule, + ], +}) +export class FuseVerticalNavigationBasicItemComponent + implements OnInit, OnDestroy +{ + private _changeDetectorRef = inject(ChangeDetectorRef); + private _fuseNavigationService = inject(FuseNavigationService); + private _fuseUtilsService = inject(FuseUtilsService); + + @Input() item: FuseNavigationItem; + @Input() name: string; + + // Set the equivalent of {exact: false} as default for active match options. + // We are not assigning the item.isActiveMatchOptions directly to the + // [routerLinkActiveOptions] because if it's "undefined" initially, the router + // will throw an error and stop working. + isActiveMatchOptions: IsActiveMatchOptions = + this._fuseUtilsService.subsetMatchOptions; + + private _fuseVerticalNavigationComponent: FuseVerticalNavigationComponent; + private _unsubscribeAll: Subject = new Subject(); + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Set the "isActiveMatchOptions" either from item's + // "isActiveMatchOptions" or the equivalent form of + // item's "exactMatch" option + this.isActiveMatchOptions = + this.item.isActiveMatchOptions ?? this.item.exactMatch + ? this._fuseUtilsService.exactMatchOptions + : this._fuseUtilsService.subsetMatchOptions; + + // Get the parent navigation component + this._fuseVerticalNavigationComponent = + this._fuseNavigationService.getComponent(this.name); + + // Mark for check + this._changeDetectorRef.markForCheck(); + + // Subscribe to onRefreshed on the navigation component + this._fuseVerticalNavigationComponent.onRefreshed + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } +} diff --git a/frontend/src/@fuse/components/navigation/vertical/components/collapsable/collapsable.component.html b/frontend/src/@fuse/components/navigation/vertical/components/collapsable/collapsable.component.html new file mode 100644 index 00000000..6dc96ff9 --- /dev/null +++ b/frontend/src/@fuse/components/navigation/vertical/components/collapsable/collapsable.component.html @@ -0,0 +1,105 @@ +
+
+ + @if (item.icon) { + + } + + +
+
+ + {{ item.title }} + +
+ @if (item.subtitle) { +
+ + {{ item.subtitle }} + +
+ } +
+ + + @if (item.badge) { +
+
+ {{ item.badge.title }} +
+
+ } + + + +
+
+ +@if (!isCollapsed) { +
+ @for (item of item.children; track trackByFn($index, item)) { + + @if ((item.hidden && !item.hidden(item)) || !item.hidden) { + + @if (item.type === 'basic') { + + } + + + @if (item.type === 'collapsable') { + + } + + + @if (item.type === 'divider') { + + } + + + @if (item.type === 'group') { + + } + + + @if (item.type === 'spacer') { + + } + } + } +
+} diff --git a/frontend/src/@fuse/components/navigation/vertical/components/collapsable/collapsable.component.ts b/frontend/src/@fuse/components/navigation/vertical/components/collapsable/collapsable.component.ts new file mode 100644 index 00000000..ca7a464d --- /dev/null +++ b/frontend/src/@fuse/components/navigation/vertical/components/collapsable/collapsable.component.ts @@ -0,0 +1,343 @@ +import { BooleanInput } from '@angular/cdk/coercion'; +import { NgClass } from '@angular/common'; +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + HostBinding, + Input, + OnDestroy, + OnInit, + forwardRef, + inject, +} from '@angular/core'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { NavigationEnd, Router } from '@angular/router'; +import { fuseAnimations } from '@fuse/animations'; +import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; +import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; +import { FuseVerticalNavigationBasicItemComponent } from '@fuse/components/navigation/vertical/components/basic/basic.component'; +import { FuseVerticalNavigationDividerItemComponent } from '@fuse/components/navigation/vertical/components/divider/divider.component'; +import { FuseVerticalNavigationGroupItemComponent } from '@fuse/components/navigation/vertical/components/group/group.component'; +import { FuseVerticalNavigationSpacerItemComponent } from '@fuse/components/navigation/vertical/components/spacer/spacer.component'; +import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component'; +import { Subject, filter, takeUntil } from 'rxjs'; + +@Component({ + selector: 'fuse-vertical-navigation-collapsable-item', + templateUrl: './collapsable.component.html', + animations: fuseAnimations, + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [ + NgClass, + MatTooltipModule, + MatIconModule, + FuseVerticalNavigationBasicItemComponent, + forwardRef(() => FuseVerticalNavigationCollapsableItemComponent), + FuseVerticalNavigationDividerItemComponent, + FuseVerticalNavigationGroupItemComponent, + FuseVerticalNavigationSpacerItemComponent, + ], +}) +export class FuseVerticalNavigationCollapsableItemComponent + implements OnInit, OnDestroy +{ + /* eslint-disable @typescript-eslint/naming-convention */ + static ngAcceptInputType_autoCollapse: BooleanInput; + /* eslint-enable @typescript-eslint/naming-convention */ + + private _changeDetectorRef = inject(ChangeDetectorRef); + private _router = inject(Router); + private _fuseNavigationService = inject(FuseNavigationService); + + @Input() autoCollapse: boolean; + @Input() item: FuseNavigationItem; + @Input() name: string; + + isCollapsed: boolean = true; + isExpanded: boolean = false; + private _fuseVerticalNavigationComponent: FuseVerticalNavigationComponent; + private _unsubscribeAll: Subject = new Subject(); + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Host binding for component classes + */ + @HostBinding('class') get classList(): any { + /* eslint-disable @typescript-eslint/naming-convention */ + return { + 'fuse-vertical-navigation-item-collapsed': this.isCollapsed, + 'fuse-vertical-navigation-item-expanded': this.isExpanded, + }; + /* eslint-enable @typescript-eslint/naming-convention */ + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Get the parent navigation component + this._fuseVerticalNavigationComponent = + this._fuseNavigationService.getComponent(this.name); + + // If the item has a children that has a matching url with the current url, expand... + if (this._hasActiveChild(this.item, this._router.url)) { + this.expand(); + } + // Otherwise... + else { + // If the autoCollapse is on, collapse... + if (this.autoCollapse) { + this.collapse(); + } + } + + // Listen for the onCollapsableItemCollapsed from the service + this._fuseVerticalNavigationComponent.onCollapsableItemCollapsed + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((collapsedItem) => { + // Check if the collapsed item is null + if (collapsedItem === null) { + return; + } + + // Collapse if this is a children of the collapsed item + if (this._isChildrenOf(collapsedItem, this.item)) { + this.collapse(); + } + }); + + // Listen for the onCollapsableItemExpanded from the service if the autoCollapse is on + if (this.autoCollapse) { + this._fuseVerticalNavigationComponent.onCollapsableItemExpanded + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((expandedItem) => { + // Check if the expanded item is null + if (expandedItem === null) { + return; + } + + // Check if this is a parent of the expanded item + if (this._isChildrenOf(this.item, expandedItem)) { + return; + } + + // Check if this has a children with a matching url with the current active url + if (this._hasActiveChild(this.item, this._router.url)) { + return; + } + + // Check if this is the expanded item + if (this.item === expandedItem) { + return; + } + + // If none of the above conditions are matched, collapse this item + this.collapse(); + }); + } + + // Attach a listener to the NavigationEnd event + this._router.events + .pipe( + filter( + (event): event is NavigationEnd => + event instanceof NavigationEnd + ), + takeUntil(this._unsubscribeAll) + ) + .subscribe((event: NavigationEnd) => { + // If the item has a children that has a matching url with the current url, expand... + if (this._hasActiveChild(this.item, event.urlAfterRedirects)) { + this.expand(); + } + // Otherwise... + else { + // If the autoCollapse is on, collapse... + if (this.autoCollapse) { + this.collapse(); + } + } + }); + + // Subscribe to onRefreshed on the navigation component + this._fuseVerticalNavigationComponent.onRefreshed + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Collapse + */ + collapse(): void { + // Return if the item is disabled + if (this.item.disabled) { + return; + } + + // Return if the item is already collapsed + if (this.isCollapsed) { + return; + } + + // Collapse it + this.isCollapsed = true; + this.isExpanded = !this.isCollapsed; + + // Mark for check + this._changeDetectorRef.markForCheck(); + + // Execute the observable + this._fuseVerticalNavigationComponent.onCollapsableItemCollapsed.next( + this.item + ); + } + + /** + * Expand + */ + expand(): void { + // Return if the item is disabled + if (this.item.disabled) { + return; + } + + // Return if the item is already expanded + if (!this.isCollapsed) { + return; + } + + // Expand it + this.isCollapsed = false; + this.isExpanded = !this.isCollapsed; + + // Mark for check + this._changeDetectorRef.markForCheck(); + + // Execute the observable + this._fuseVerticalNavigationComponent.onCollapsableItemExpanded.next( + this.item + ); + } + + /** + * Toggle collapsable + */ + toggleCollapsable(): void { + // Toggle collapse/expand + if (this.isCollapsed) { + this.expand(); + } else { + this.collapse(); + } + } + + /** + * Track by function for ngFor loops + * + * @param index + * @param item + */ + trackByFn(index: number, item: any): any { + return item.id || index; + } + + // ----------------------------------------------------------------------------------------------------- + // @ Private methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Check if the given item has the given url + * in one of its children + * + * @param item + * @param currentUrl + * @private + */ + private _hasActiveChild( + item: FuseNavigationItem, + currentUrl: string + ): boolean { + const children = item.children; + + if (!children) { + return false; + } + + for (const child of children) { + if (child.children) { + if (this._hasActiveChild(child, currentUrl)) { + return true; + } + } + + // Check if the child has a link and is active + if ( + child.link && + this._router.isActive(child.link, child.exactMatch || false) + ) { + return true; + } + } + + return false; + } + + /** + * Check if this is a children + * of the given item + * + * @param parent + * @param item + * @private + */ + private _isChildrenOf( + parent: FuseNavigationItem, + item: FuseNavigationItem + ): boolean { + const children = parent.children; + + if (!children) { + return false; + } + + if (children.indexOf(item) > -1) { + return true; + } + + for (const child of children) { + if (child.children) { + if (this._isChildrenOf(child, item)) { + return true; + } + } + } + + return false; + } +} diff --git a/frontend/src/@fuse/components/navigation/vertical/components/divider/divider.component.html b/frontend/src/@fuse/components/navigation/vertical/components/divider/divider.component.html new file mode 100644 index 00000000..cc421f74 --- /dev/null +++ b/frontend/src/@fuse/components/navigation/vertical/components/divider/divider.component.html @@ -0,0 +1,5 @@ + +
diff --git a/frontend/src/@fuse/components/navigation/vertical/components/divider/divider.component.ts b/frontend/src/@fuse/components/navigation/vertical/components/divider/divider.component.ts new file mode 100644 index 00000000..4794e91c --- /dev/null +++ b/frontend/src/@fuse/components/navigation/vertical/components/divider/divider.component.ts @@ -0,0 +1,64 @@ +import { NgClass } from '@angular/common'; +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + inject, + Input, + OnDestroy, + OnInit, +} from '@angular/core'; +import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; +import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; +import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component'; +import { Subject, takeUntil } from 'rxjs'; + +@Component({ + selector: 'fuse-vertical-navigation-divider-item', + templateUrl: './divider.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [NgClass], +}) +export class FuseVerticalNavigationDividerItemComponent + implements OnInit, OnDestroy +{ + private _changeDetectorRef = inject(ChangeDetectorRef); + private _fuseNavigationService = inject(FuseNavigationService); + + @Input() item: FuseNavigationItem; + @Input() name: string; + + private _fuseVerticalNavigationComponent: FuseVerticalNavigationComponent; + private _unsubscribeAll: Subject = new Subject(); + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Get the parent navigation component + this._fuseVerticalNavigationComponent = + this._fuseNavigationService.getComponent(this.name); + + // Subscribe to onRefreshed on the navigation component + this._fuseVerticalNavigationComponent.onRefreshed + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } +} diff --git a/frontend/src/@fuse/components/navigation/vertical/components/group/group.component.html b/frontend/src/@fuse/components/navigation/vertical/components/group/group.component.html new file mode 100644 index 00000000..efdf0218 --- /dev/null +++ b/frontend/src/@fuse/components/navigation/vertical/components/group/group.component.html @@ -0,0 +1,91 @@ + +
+
+ + @if (item.icon) { + + } + + +
+
+ + {{ item.title }} + +
+ @if (item.subtitle) { +
+ + {{ item.subtitle }} + +
+ } +
+ + + @if (item.badge) { +
+
+ {{ item.badge.title }} +
+
+ } +
+
+ +@for (item of item.children; track trackByFn($index, item)) { + + @if ((item.hidden && !item.hidden(item)) || !item.hidden) { + + @if (item.type === 'basic') { + + } + + + @if (item.type === 'collapsable') { + + } + + + @if (item.type === 'divider') { + + } + + + @if (item.type === 'group') { + + } + + + @if (item.type === 'spacer') { + + } + } +} diff --git a/frontend/src/@fuse/components/navigation/vertical/components/group/group.component.ts b/frontend/src/@fuse/components/navigation/vertical/components/group/group.component.ts new file mode 100644 index 00000000..9a959537 --- /dev/null +++ b/frontend/src/@fuse/components/navigation/vertical/components/group/group.component.ts @@ -0,0 +1,98 @@ +import { BooleanInput } from '@angular/cdk/coercion'; +import { NgClass } from '@angular/common'; +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + Input, + OnDestroy, + OnInit, + forwardRef, + inject, +} from '@angular/core'; +import { MatIconModule } from '@angular/material/icon'; +import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; +import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; +import { FuseVerticalNavigationBasicItemComponent } from '@fuse/components/navigation/vertical/components/basic/basic.component'; +import { FuseVerticalNavigationCollapsableItemComponent } from '@fuse/components/navigation/vertical/components/collapsable/collapsable.component'; +import { FuseVerticalNavigationDividerItemComponent } from '@fuse/components/navigation/vertical/components/divider/divider.component'; +import { FuseVerticalNavigationSpacerItemComponent } from '@fuse/components/navigation/vertical/components/spacer/spacer.component'; +import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component'; +import { Subject, takeUntil } from 'rxjs'; + +@Component({ + selector: 'fuse-vertical-navigation-group-item', + templateUrl: './group.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [ + NgClass, + MatIconModule, + FuseVerticalNavigationBasicItemComponent, + FuseVerticalNavigationCollapsableItemComponent, + FuseVerticalNavigationDividerItemComponent, + forwardRef(() => FuseVerticalNavigationGroupItemComponent), + FuseVerticalNavigationSpacerItemComponent, + ], +}) +export class FuseVerticalNavigationGroupItemComponent + implements OnInit, OnDestroy +{ + /* eslint-disable @typescript-eslint/naming-convention */ + static ngAcceptInputType_autoCollapse: BooleanInput; + /* eslint-enable @typescript-eslint/naming-convention */ + + private _changeDetectorRef = inject(ChangeDetectorRef); + private _fuseNavigationService = inject(FuseNavigationService); + + @Input() autoCollapse: boolean; + @Input() item: FuseNavigationItem; + @Input() name: string; + + private _fuseVerticalNavigationComponent: FuseVerticalNavigationComponent; + private _unsubscribeAll: Subject = new Subject(); + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Get the parent navigation component + this._fuseVerticalNavigationComponent = + this._fuseNavigationService.getComponent(this.name); + + // Subscribe to onRefreshed on the navigation component + this._fuseVerticalNavigationComponent.onRefreshed + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Track by function for ngFor loops + * + * @param index + * @param item + */ + trackByFn(index: number, item: any): any { + return item.id || index; + } +} diff --git a/frontend/src/@fuse/components/navigation/vertical/components/spacer/spacer.component.html b/frontend/src/@fuse/components/navigation/vertical/components/spacer/spacer.component.html new file mode 100644 index 00000000..b6e7108d --- /dev/null +++ b/frontend/src/@fuse/components/navigation/vertical/components/spacer/spacer.component.html @@ -0,0 +1,5 @@ + +
diff --git a/frontend/src/@fuse/components/navigation/vertical/components/spacer/spacer.component.ts b/frontend/src/@fuse/components/navigation/vertical/components/spacer/spacer.component.ts new file mode 100644 index 00000000..b4bfe232 --- /dev/null +++ b/frontend/src/@fuse/components/navigation/vertical/components/spacer/spacer.component.ts @@ -0,0 +1,64 @@ +import { NgClass } from '@angular/common'; +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + inject, + Input, + OnDestroy, + OnInit, +} from '@angular/core'; +import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; +import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; +import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component'; +import { Subject, takeUntil } from 'rxjs'; + +@Component({ + selector: 'fuse-vertical-navigation-spacer-item', + templateUrl: './spacer.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [NgClass], +}) +export class FuseVerticalNavigationSpacerItemComponent + implements OnInit, OnDestroy +{ + private _changeDetectorRef = inject(ChangeDetectorRef); + private _fuseNavigationService = inject(FuseNavigationService); + + @Input() item: FuseNavigationItem; + @Input() name: string; + + private _fuseVerticalNavigationComponent: FuseVerticalNavigationComponent; + private _unsubscribeAll: Subject = new Subject(); + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Get the parent navigation component + this._fuseVerticalNavigationComponent = + this._fuseNavigationService.getComponent(this.name); + + // Subscribe to onRefreshed on the navigation component + this._fuseVerticalNavigationComponent.onRefreshed + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } +} diff --git a/frontend/src/@fuse/components/navigation/vertical/styles/appearances/compact.scss b/frontend/src/@fuse/components/navigation/vertical/styles/appearances/compact.scss new file mode 100644 index 00000000..e0ed13f2 --- /dev/null +++ b/frontend/src/@fuse/components/navigation/vertical/styles/appearances/compact.scss @@ -0,0 +1,109 @@ +/* Variables */ +:root { + --fuse-vertical-navigation-compact-width: 112px; +} + +fuse-vertical-navigation { + /* Compact appearance overrides */ + &.fuse-vertical-navigation-appearance-compact { + width: var(--fuse-vertical-navigation-compact-width); + min-width: var(--fuse-vertical-navigation-compact-width); + max-width: var(--fuse-vertical-navigation-compact-width); + + /* Left positioned */ + &.fuse-vertical-navigation-position-left { + /* Side mode */ + &.fuse-vertical-navigation-mode-side { + margin-left: calc( + var(--fuse-vertical-navigation-compact-width) * -1 + ); + } + + /* Opened */ + &.fuse-vertical-navigation-opened { + margin-left: 0; + } + } + + /* Right positioned */ + &.fuse-vertical-navigation-position-right { + /* Side mode */ + &.fuse-vertical-navigation-mode-side { + margin-right: calc( + var(--fuse-vertical-navigation-compact-width) * -1 + ); + } + + /* Opened */ + &.fuse-vertical-navigation-opened { + margin-right: 0; + } + + /* Aside wrapper */ + .fuse-vertical-navigation-aside-wrapper { + left: auto; + right: var(--fuse-vertical-navigation-compact-width); + } + } + + /* Wrapper */ + .fuse-vertical-navigation-wrapper { + /* Content */ + .fuse-vertical-navigation-content { + > fuse-vertical-navigation-aside-item, + > fuse-vertical-navigation-basic-item { + .fuse-vertical-navigation-item-wrapper { + margin: 4px 8px 0 8px; + + .fuse-vertical-navigation-item { + flex-direction: column; + justify-content: center; + padding: 12px; + border-radius: 6px; + + .fuse-vertical-navigation-item-icon { + margin-right: 0; + } + + .fuse-vertical-navigation-item-title-wrapper { + margin-top: 8px; + + .fuse-vertical-navigation-item-title { + font-size: 12px; + font-weight: 500; + text-align: center; + line-height: 16px; + } + + .fuse-vertical-navigation-item-subtitle { + display: none !important; + } + } + + .fuse-vertical-navigation-item-badge { + position: absolute; + top: 12px; + left: 64px; + } + } + } + + > fuse-vertical-navigation-collapsable-item { + display: none; + } + + > fuse-vertical-navigation-group-item { + > .fuse-vertical-navigation-item-wrapper { + display: none; + } + } + } + } + } + + /* Aside wrapper */ + .fuse-vertical-navigation-aside-wrapper { + left: var(--fuse-vertical-navigation-compact-width); + } + } +} diff --git a/frontend/src/@fuse/components/navigation/vertical/styles/appearances/default.scss b/frontend/src/@fuse/components/navigation/vertical/styles/appearances/default.scss new file mode 100644 index 00000000..2fe8d7cf --- /dev/null +++ b/frontend/src/@fuse/components/navigation/vertical/styles/appearances/default.scss @@ -0,0 +1,559 @@ +/* Variables */ +:root { + --fuse-vertical-navigation-width: 280px; +} + +fuse-vertical-navigation { + position: sticky; + display: flex; + flex-direction: column; + flex: 1 0 auto; + top: 0; + width: var(--fuse-vertical-navigation-width); + min-width: var(--fuse-vertical-navigation-width); + max-width: var(--fuse-vertical-navigation-width); + height: 100vh; + min-height: 100vh; + max-height: 100vh; + z-index: 200; + + /* ----------------------------------------------------------------------------------------------------- */ + /* @ Navigation Drawer + /* ----------------------------------------------------------------------------------------------------- */ + + /* Animations */ + &.fuse-vertical-navigation-animations-enabled { + transition-duration: 400ms; + transition-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1); + transition-property: visibility, margin-left, margin-right, transform, + width, max-width, min-width; + + /* Wrapper */ + .fuse-vertical-navigation-wrapper { + transition-duration: 400ms; + transition-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1); + transition-property: width, max-width, min-width; + } + } + + /* Over mode */ + &.fuse-vertical-navigation-mode-over { + position: fixed; + top: 0; + bottom: 0; + } + + /* Left position */ + &.fuse-vertical-navigation-position-left { + /* Side mode */ + &.fuse-vertical-navigation-mode-side { + margin-left: calc(#{var(--fuse-vertical-navigation-width)} * -1); + + &.fuse-vertical-navigation-opened { + margin-left: 0; + } + } + + /* Over mode */ + &.fuse-vertical-navigation-mode-over { + left: 0; + transform: translate3d(-100%, 0, 0); + + &.fuse-vertical-navigation-opened { + transform: translate3d(0, 0, 0); + } + } + + /* Wrapper */ + .fuse-vertical-navigation-wrapper { + left: 0; + } + } + + /* Right position */ + &.fuse-vertical-navigation-position-right { + /* Side mode */ + &.fuse-vertical-navigation-mode-side { + margin-right: calc(var(--fuse-vertical-navigation-width) * -1); + + &.fuse-vertical-navigation-opened { + margin-right: 0; + } + } + + /* Over mode */ + &.fuse-vertical-navigation-mode-over { + right: 0; + transform: translate3d(100%, 0, 0); + + &.fuse-vertical-navigation-opened { + transform: translate3d(0, 0, 0); + } + } + + /* Wrapper */ + .fuse-vertical-navigation-wrapper { + right: 0; + } + } + + /* Inner mode */ + &.fuse-vertical-navigation-inner { + position: relative; + width: auto; + min-width: 0; + max-width: none; + height: auto; + min-height: 0; + max-height: none; + box-shadow: none; + + .fuse-vertical-navigation-wrapper { + position: relative; + overflow: visible; + height: auto; + + .fuse-vertical-navigation-content { + overflow: visible !important; + } + } + } + + /* Wrapper */ + .fuse-vertical-navigation-wrapper { + position: absolute; + display: flex; + flex: 1 1 auto; + flex-direction: column; + top: 0; + bottom: 0; + width: 100%; + height: 100%; + overflow: hidden; + z-index: 10; + background: inherit; + box-shadow: inset -1px 0 0 var(--fuse-border); + + /* Header */ + .fuse-vertical-navigation-header { + } + + /* Content */ + .fuse-vertical-navigation-content { + flex: 1 1 auto; + overflow-x: hidden; + overflow-y: auto; + overscroll-behavior: contain; + + /* Divider */ + > fuse-vertical-navigation-divider-item { + margin: 24px 0; + } + + /* Group */ + > fuse-vertical-navigation-group-item { + margin-top: 24px; + } + } + + /* Footer */ + .fuse-vertical-navigation-footer { + } + } + + /* Aside wrapper */ + .fuse-vertical-navigation-aside-wrapper { + position: absolute; + display: flex; + flex: 1 1 auto; + flex-direction: column; + top: 0; + bottom: 0; + left: var(--fuse-vertical-navigation-width); + width: var(--fuse-vertical-navigation-width); + height: 100%; + z-index: 5; + overflow-x: hidden; + overflow-y: auto; + -webkit-overflow-scrolling: touch; + transition-duration: 400ms; + transition-property: left, right; + transition-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1); + background: inherit; + + > fuse-vertical-navigation-aside-item { + padding: 24px 0; + + /* First item of the aside */ + > .fuse-vertical-navigation-item-wrapper { + display: none !important; + } + } + } + + &.fuse-vertical-navigation-position-right { + .fuse-vertical-navigation-aside-wrapper { + left: auto; + right: var(--fuse-vertical-navigation-width); + } + } + + /* ----------------------------------------------------------------------------------------------------- */ + /* @ Navigation Items + /* ----------------------------------------------------------------------------------------------------- */ + + /* Navigation items common */ + fuse-vertical-navigation-aside-item, + fuse-vertical-navigation-basic-item, + fuse-vertical-navigation-collapsable-item, + fuse-vertical-navigation-divider-item, + fuse-vertical-navigation-group-item, + fuse-vertical-navigation-spacer-item { + display: flex; + flex-direction: column; + flex: 1 0 auto; + user-select: none; + + .fuse-vertical-navigation-item-wrapper { + .fuse-vertical-navigation-item { + position: relative; + display: flex; + align-items: center; + justify-content: flex-start; + padding: 10px 16px; + font-size: 13px; + font-weight: 500; + line-height: 20px; + text-decoration: none; + border-radius: 6px; + + /* Disabled state */ + &.fuse-vertical-navigation-item-disabled { + cursor: default; + opacity: 0.4; + } + + .fuse-vertical-navigation-item-icon { + margin-right: 16px; + } + + .fuse-vertical-navigation-item-title-wrapper { + .fuse-vertical-navigation-item-subtitle { + font-size: 11px; + line-height: 1.5; + } + } + + .fuse-vertical-navigation-item-badge { + margin-left: auto; + + .fuse-vertical-navigation-item-badge-content { + display: flex; + align-items: center; + justify-content: center; + font-size: 10px; + font-weight: 600; + white-space: nowrap; + height: 20px; + } + } + } + } + } + + /* Aside, Basic, Collapsable, Group */ + fuse-vertical-navigation-aside-item, + fuse-vertical-navigation-basic-item, + fuse-vertical-navigation-collapsable-item, + fuse-vertical-navigation-group-item { + > .fuse-vertical-navigation-item-wrapper { + margin: 0 12px; + } + } + + /* Aside, Basic, Collapsable */ + fuse-vertical-navigation-aside-item, + fuse-vertical-navigation-basic-item, + fuse-vertical-navigation-collapsable-item { + margin-bottom: 4px; + + .fuse-vertical-navigation-item { + cursor: pointer; + } + } + + /* Aside */ + fuse-vertical-navigation-aside-item { + } + + /* Basic */ + fuse-vertical-navigation-basic-item { + } + + /* Collapsable */ + fuse-vertical-navigation-collapsable-item { + > .fuse-vertical-navigation-item-wrapper { + .fuse-vertical-navigation-item { + .fuse-vertical-navigation-item-badge { + + .fuse-vertical-navigation-item-arrow { + margin-left: 8px; + } + } + + .fuse-vertical-navigation-item-arrow { + height: 20px; + line-height: 20px; + margin-left: auto; + transition: + transform 300ms cubic-bezier(0.25, 0.8, 0.25, 1), + color 375ms cubic-bezier(0.25, 0.8, 0.25, 1); + } + } + } + + &.fuse-vertical-navigation-item-expanded { + > .fuse-vertical-navigation-item-wrapper { + .fuse-vertical-navigation-item { + .fuse-vertical-navigation-item-arrow { + transform: rotate(90deg); + } + } + } + } + + > .fuse-vertical-navigation-item-children { + > *:first-child { + margin-top: 6px; + } + + > *:last-child { + padding-bottom: 6px; + + > .fuse-vertical-navigation-item-children { + > *:last-child { + padding-bottom: 0; + } + } + } + + .fuse-vertical-navigation-item { + padding: 10px 16px; + } + } + + /* 1st level */ + .fuse-vertical-navigation-item-children { + overflow: hidden; + + .fuse-vertical-navigation-item { + padding-left: 56px; + } + + /* 2nd level */ + .fuse-vertical-navigation-item-children { + .fuse-vertical-navigation-item { + padding-left: 72px; + } + + /* 3rd level */ + .fuse-vertical-navigation-item-children { + .fuse-vertical-navigation-item { + padding-left: 88px; + } + + /* 4th level */ + .fuse-vertical-navigation-item-children { + .fuse-vertical-navigation-item { + padding-left: 104px; + } + } + } + } + } + } + + /* Divider */ + fuse-vertical-navigation-divider-item { + margin: 12px 0; + + .fuse-vertical-navigation-item-wrapper { + height: 1px; + box-shadow: 0 1px 0 0; + } + } + + /* Group */ + fuse-vertical-navigation-group-item { + > .fuse-vertical-navigation-item-wrapper { + .fuse-vertical-navigation-item { + .fuse-vertical-navigation-item-badge, + .fuse-vertical-navigation-item-icon { + display: none !important; + } + + .fuse-vertical-navigation-item-title-wrapper { + .fuse-vertical-navigation-item-title { + font-size: 12px; + font-weight: 600; + letter-spacing: 0.05em; + text-transform: uppercase; + } + } + } + } + } + + /* Spacer */ + fuse-vertical-navigation-spacer-item { + margin: 6px 0; + } +} + +/* ----------------------------------------------------------------------------------------------------- */ +/* @ Overlay +/* ----------------------------------------------------------------------------------------------------- */ +.fuse-vertical-navigation-overlay { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: 170; + opacity: 0; + background-color: rgba(0, 0, 0, 0.6); + + + .fuse-vertical-navigation-aside-overlay { + background-color: transparent; + } +} + +/* ----------------------------------------------------------------------------------------------------- */ +/* @ Aside overlay +/* ----------------------------------------------------------------------------------------------------- */ +.fuse-vertical-navigation-aside-overlay { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: 169; + opacity: 0; + background-color: rgba(0, 0, 0, 0.3); +} + +/* ----------------------------------------------------------------------------------------------------- */ +/* @ Navigation Items Colors +/* ----------------------------------------------------------------------------------------------------- */ + +/* Navigation items common */ +fuse-vertical-navigation-aside-item, +fuse-vertical-navigation-basic-item, +fuse-vertical-navigation-collapsable-item, +fuse-vertical-navigation-group-item { + .fuse-vertical-navigation-item-wrapper { + .fuse-vertical-navigation-item { + color: currentColor; + + .fuse-vertical-navigation-item-icon { + @apply text-current opacity-60; + } + + .fuse-vertical-navigation-item-title-wrapper { + .fuse-vertical-navigation-item-title { + @apply text-current opacity-80; + } + + .fuse-vertical-navigation-item-subtitle { + @apply text-current opacity-50; + } + } + } + } +} + +/* Aside, Basic, Collapsable */ +fuse-vertical-navigation-aside-item, +fuse-vertical-navigation-basic-item, +fuse-vertical-navigation-collapsable-item { + > .fuse-vertical-navigation-item-wrapper { + .fuse-vertical-navigation-item { + /* Active state */ + &:not(.fuse-vertical-navigation-item-disabled) { + &.fuse-vertical-navigation-item-active, + &.fuse-vertical-navigation-item-active-forced { + @apply bg-gray-800 bg-opacity-5 dark:bg-white dark:bg-opacity-12; + + .fuse-vertical-navigation-item-icon { + @apply opacity-100; + } + + .fuse-vertical-navigation-item-title { + @apply opacity-100; + } + + .fuse-vertical-navigation-item-subtitle { + @apply opacity-100; + } + } + } + + /* Hover state */ + &:not(.fuse-vertical-navigation-item-active-forced):not( + .fuse-vertical-navigation-item-active + ):not(.fuse-vertical-navigation-item-disabled) { + &:hover { + @apply bg-gray-800 bg-opacity-5 dark:bg-white dark:bg-opacity-12; + + .fuse-vertical-navigation-item-icon { + @apply opacity-100; + } + + .fuse-vertical-navigation-item-title, + .fuse-vertical-navigation-item-arrow { + @apply opacity-100; + } + + .fuse-vertical-navigation-item-subtitle { + @apply opacity-100; + } + } + } + } + } +} + +/* Collapsable */ +fuse-vertical-navigation-collapsable-item { + /* Expanded state */ + &.fuse-vertical-navigation-item-expanded { + > .fuse-vertical-navigation-item-wrapper { + .fuse-vertical-navigation-item { + .fuse-vertical-navigation-item-icon { + @apply opacity-100; + } + + .fuse-vertical-navigation-item-title, + .fuse-vertical-navigation-item-arrow { + @apply opacity-100; + } + + .fuse-vertical-navigation-item-subtitle { + @apply opacity-100; + } + } + } + } +} + +/* Group */ +fuse-vertical-navigation-group-item { + > .fuse-vertical-navigation-item-wrapper { + .fuse-vertical-navigation-item { + .fuse-vertical-navigation-item-title-wrapper { + .fuse-vertical-navigation-item-title { + @apply text-primary-600 opacity-100 dark:text-primary-400; + } + } + } + } +} diff --git a/frontend/src/@fuse/components/navigation/vertical/styles/appearances/dense.scss b/frontend/src/@fuse/components/navigation/vertical/styles/appearances/dense.scss new file mode 100644 index 00000000..6eb7a362 --- /dev/null +++ b/frontend/src/@fuse/components/navigation/vertical/styles/appearances/dense.scss @@ -0,0 +1,196 @@ +/* Variables */ +:root { + --fuse-vertical-navigation-width: 280px; + --fuse-vertical-navigation-dense-width: 80px; +} + +fuse-vertical-navigation { + /* Dense appearance overrides */ + &.fuse-vertical-navigation-appearance-dense { + &:not(.fuse-vertical-navigation-mode-over) { + width: var(--fuse-vertical-navigation-dense-width); + min-width: var(--fuse-vertical-navigation-dense-width); + max-width: var(--fuse-vertical-navigation-dense-width); + + /* Left positioned */ + &.fuse-vertical-navigation-position-left { + /* Side mode */ + &.fuse-vertical-navigation-mode-side { + margin-left: calc( + var(--fuse-vertical-navigation-dense-width) * -1 + ); + } + + /* Opened */ + &.fuse-vertical-navigation-opened { + margin-left: 0; + } + } + + /* Right positioned */ + &.fuse-vertical-navigation-position-right { + /* Side mode */ + &.fuse-vertical-navigation-mode-side { + margin-right: calc( + var(--fuse-vertical-navigation-dense-width) * -1 + ); + } + + /* Opened */ + &.fuse-vertical-navigation-opened { + margin-right: 0; + } + + /* Aside wrapper */ + .fuse-vertical-navigation-aside-wrapper { + left: auto; + right: var(--fuse-vertical-navigation-dense-width); + } + + &.fuse-vertical-navigation-hover { + .fuse-vertical-navigation-aside-wrapper { + left: auto; + right: var(--fuse-vertical-navigation-width); + } + } + } + } + + /* Wrapper */ + .fuse-vertical-navigation-wrapper { + /* Content */ + .fuse-vertical-navigation-content { + fuse-vertical-navigation-aside-item, + fuse-vertical-navigation-basic-item, + fuse-vertical-navigation-collapsable-item, + fuse-vertical-navigation-group-item { + .fuse-vertical-navigation-item-wrapper { + .fuse-vertical-navigation-item { + width: calc( + var(--fuse-vertical-navigation-dense-width) - + 24px + ); + min-width: calc( + var(--fuse-vertical-navigation-dense-width) - + 24px + ); + max-width: calc( + var(--fuse-vertical-navigation-dense-width) - + 24px + ); + + .fuse-vertical-navigation-item-arrow, + .fuse-vertical-navigation-item-badge, + .fuse-vertical-navigation-item-title-wrapper { + transition: opacity 400ms + cubic-bezier(0.25, 0.8, 0.25, 1); + } + } + } + } + + fuse-vertical-navigation-group-item { + &:first-of-type { + margin-top: 0; + } + } + } + } + + &:not(.fuse-vertical-navigation-hover):not( + .fuse-vertical-navigation-mode-over + ) { + /* Wrapper */ + .fuse-vertical-navigation-wrapper { + /* Content */ + .fuse-vertical-navigation-content { + .fuse-vertical-navigation-item-wrapper { + .fuse-vertical-navigation-item { + padding: 10px 16px; + + .fuse-vertical-navigation-item-arrow, + .fuse-vertical-navigation-item-badge, + .fuse-vertical-navigation-item-title-wrapper { + white-space: nowrap; + opacity: 0; + } + } + } + + fuse-vertical-navigation-collapsable-item { + .fuse-vertical-navigation-item-children { + display: none; + } + } + + fuse-vertical-navigation-group-item { + > .fuse-vertical-navigation-item-wrapper { + .fuse-vertical-navigation-item { + &:before { + content: ''; + position: absolute; + top: 20px; + width: 23px; + border-top-width: 2px; + } + } + } + } + } + } + } + + /* Aside wrapper */ + .fuse-vertical-navigation-aside-wrapper { + left: var(--fuse-vertical-navigation-dense-width); + } + + /* Hover */ + &.fuse-vertical-navigation-hover { + .fuse-vertical-navigation-wrapper { + width: var(--fuse-vertical-navigation-width); + + .fuse-vertical-navigation-content { + .fuse-vertical-navigation-item-wrapper { + .fuse-vertical-navigation-item { + width: calc( + var(--fuse-vertical-navigation-width) - 24px + ); + min-width: calc( + var(--fuse-vertical-navigation-width) - 24px + ); + max-width: calc( + var(--fuse-vertical-navigation-width) - 24px + ); + + .fuse-vertical-navigation-item-arrow, + .fuse-vertical-navigation-item-badge, + .fuse-vertical-navigation-item-title-wrapper { + white-space: nowrap; + animation: removeWhiteSpaceNoWrap 1ms linear + 350ms; + animation-fill-mode: forwards; + } + } + } + } + } + + .fuse-vertical-navigation-aside-wrapper { + left: var(--fuse-vertical-navigation-width); + } + } + } +} + +@keyframes removeWhiteSpaceNoWrap { + 0% { + white-space: nowrap; + } + 99% { + white-space: nowrap; + } + 100% { + white-space: normal; + } +} diff --git a/frontend/src/@fuse/components/navigation/vertical/styles/appearances/thin.scss b/frontend/src/@fuse/components/navigation/vertical/styles/appearances/thin.scss new file mode 100644 index 00000000..baeff73b --- /dev/null +++ b/frontend/src/@fuse/components/navigation/vertical/styles/appearances/thin.scss @@ -0,0 +1,97 @@ +/* Variables */ +:root { + --fuse-vertical-navigation-thin-width: 80px; +} + +fuse-vertical-navigation { + /* Thin appearance overrides */ + &.fuse-vertical-navigation-appearance-thin { + width: var(--fuse-vertical-navigation-thin-width); + min-width: var(--fuse-vertical-navigation-thin-width); + max-width: var(--fuse-vertical-navigation-thin-width); + + /* Left positioned */ + &.fuse-vertical-navigation-position-left { + &.fuse-vertical-navigation-mode-side { + margin-left: calc( + var(--fuse-vertical-navigation-thin-width) * -1 + ); + } + + &.fuse-vertical-navigation-opened { + margin-left: 0; + } + } + + /* Right positioned */ + &.fuse-vertical-navigation-position-right { + &.fuse-vertical-navigation-mode-side { + margin-right: calc( + var(--fuse-vertical-navigation-thin-width) * -1 + ); + } + + &.fuse-vertical-navigation-opened { + margin-right: 0; + } + + .fuse-vertical-navigation-aside-wrapper { + left: auto; + right: var(--fuse-vertical-navigation-thin-width); + } + } + + /* Wrapper */ + .fuse-vertical-navigation-wrapper { + /* Content */ + .fuse-vertical-navigation-content { + > fuse-vertical-navigation-aside-item, + > fuse-vertical-navigation-basic-item { + flex-direction: column; + justify-content: center; + height: 64px; + min-height: 64px; + max-height: 64px; + padding: 0 16px; + + .fuse-vertical-navigation-item-wrapper { + display: flex; + align-items: center; + justify-content: center; + + .fuse-vertical-navigation-item { + justify-content: center; + padding: 12px; + border-radius: 4px; + + .fuse-vertical-navigation-item-icon { + margin: 0; + } + + .fuse-vertical-navigation-item-arrow, + .fuse-vertical-navigation-item-badge-content, + .fuse-vertical-navigation-item-title-wrapper { + display: none; + } + } + } + } + + > fuse-vertical-navigation-collapsable-item { + display: none; + } + + > fuse-vertical-navigation-group-item { + > .fuse-vertical-navigation-item-wrapper { + display: none; + } + } + } + } + + /* Aside wrapper */ + .fuse-vertical-navigation-aside-wrapper { + left: var(--fuse-vertical-navigation-thin-width); + } + } +} diff --git a/frontend/src/@fuse/components/navigation/vertical/vertical.component.html b/frontend/src/@fuse/components/navigation/vertical/vertical.component.html new file mode 100644 index 00000000..f925b6a8 --- /dev/null +++ b/frontend/src/@fuse/components/navigation/vertical/vertical.component.html @@ -0,0 +1,127 @@ +
+ +
+ +
+ + +
+ +
+ +
+ + + @for (item of navigation; track trackByFn($index, item)) { + + @if ((item.hidden && !item.hidden(item)) || !item.hidden) { + + @if (item.type === 'aside') { + + } + + + @if (item.type === 'basic') { + + } + + + @if (item.type === 'collapsable') { + + } + + + @if (item.type === 'divider') { + + } + + + @if (item.type === 'group') { + + } + + + @if (item.type === 'spacer') { + + } + } + } + + + +
+ + + +
+ + +@if (activeAsideItemId) { +
+ + @for (item of navigation; track trackByFn($index, item)) { + + @if ((item.hidden && !item.hidden(item)) || !item.hidden) { + + @if (item.type === 'aside' && item.id === activeAsideItemId) { + + } + } + } +
+} diff --git a/frontend/src/@fuse/components/navigation/vertical/vertical.component.scss b/frontend/src/@fuse/components/navigation/vertical/vertical.component.scss new file mode 100644 index 00000000..ea2db443 --- /dev/null +++ b/frontend/src/@fuse/components/navigation/vertical/vertical.component.scss @@ -0,0 +1,4 @@ +@use 'styles/appearances/default'; +@use 'styles/appearances/compact'; +@use 'styles/appearances/dense'; +@use 'styles/appearances/thin'; diff --git a/frontend/src/@fuse/components/navigation/vertical/vertical.component.ts b/frontend/src/@fuse/components/navigation/vertical/vertical.component.ts new file mode 100644 index 00000000..446afcf9 --- /dev/null +++ b/frontend/src/@fuse/components/navigation/vertical/vertical.component.ts @@ -0,0 +1,831 @@ +import { + animate, + AnimationBuilder, + AnimationPlayer, + style, +} from '@angular/animations'; +import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion'; +import { ScrollStrategy, ScrollStrategyOptions } from '@angular/cdk/overlay'; +import { DOCUMENT } from '@angular/common'; +import { + AfterViewInit, + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + ElementRef, + EventEmitter, + HostBinding, + HostListener, + inject, + Input, + OnChanges, + OnDestroy, + OnInit, + Output, + QueryList, + Renderer2, + SimpleChanges, + ViewChild, + ViewChildren, + ViewEncapsulation, +} from '@angular/core'; +import { NavigationEnd, Router } from '@angular/router'; +import { fuseAnimations } from '@fuse/animations'; +import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; +import { + FuseNavigationItem, + FuseVerticalNavigationAppearance, + FuseVerticalNavigationMode, + FuseVerticalNavigationPosition, +} from '@fuse/components/navigation/navigation.types'; +import { FuseVerticalNavigationAsideItemComponent } from '@fuse/components/navigation/vertical/components/aside/aside.component'; +import { FuseVerticalNavigationBasicItemComponent } from '@fuse/components/navigation/vertical/components/basic/basic.component'; +import { FuseVerticalNavigationCollapsableItemComponent } from '@fuse/components/navigation/vertical/components/collapsable/collapsable.component'; +import { FuseVerticalNavigationDividerItemComponent } from '@fuse/components/navigation/vertical/components/divider/divider.component'; +import { FuseVerticalNavigationGroupItemComponent } from '@fuse/components/navigation/vertical/components/group/group.component'; +import { FuseVerticalNavigationSpacerItemComponent } from '@fuse/components/navigation/vertical/components/spacer/spacer.component'; +import { FuseScrollbarDirective } from '@fuse/directives/scrollbar/scrollbar.directive'; +import { FuseUtilsService } from '@fuse/services/utils/utils.service'; +import { + delay, + filter, + merge, + ReplaySubject, + Subject, + Subscription, + takeUntil, +} from 'rxjs'; + +@Component({ + selector: 'fuse-vertical-navigation', + templateUrl: './vertical.component.html', + styleUrls: ['./vertical.component.scss'], + animations: fuseAnimations, + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + exportAs: 'fuseVerticalNavigation', + standalone: true, + imports: [ + FuseScrollbarDirective, + FuseVerticalNavigationAsideItemComponent, + FuseVerticalNavigationBasicItemComponent, + FuseVerticalNavigationCollapsableItemComponent, + FuseVerticalNavigationDividerItemComponent, + FuseVerticalNavigationGroupItemComponent, + FuseVerticalNavigationSpacerItemComponent, + ], +}) +export class FuseVerticalNavigationComponent + implements OnChanges, OnInit, AfterViewInit, OnDestroy +{ + /* eslint-disable @typescript-eslint/naming-convention */ + static ngAcceptInputType_inner: BooleanInput; + static ngAcceptInputType_opened: BooleanInput; + static ngAcceptInputType_transparentOverlay: BooleanInput; + /* eslint-enable @typescript-eslint/naming-convention */ + + private _animationBuilder = inject(AnimationBuilder); + private _changeDetectorRef = inject(ChangeDetectorRef); + private _document = inject(DOCUMENT); + private _elementRef = inject(ElementRef); + private _renderer2 = inject(Renderer2); + private _router = inject(Router); + private _scrollStrategyOptions = inject(ScrollStrategyOptions); + private _fuseNavigationService = inject(FuseNavigationService); + private _fuseUtilsService = inject(FuseUtilsService); + + @Input() appearance: FuseVerticalNavigationAppearance = 'default'; + @Input() autoCollapse: boolean = true; + @Input() inner: boolean = false; + @Input() mode: FuseVerticalNavigationMode = 'side'; + @Input() name: string = this._fuseUtilsService.randomId(); + @Input() navigation: FuseNavigationItem[]; + @Input() opened: boolean = true; + @Input() position: FuseVerticalNavigationPosition = 'left'; + @Input() transparentOverlay: boolean = false; + @Output() + readonly appearanceChanged: EventEmitter = + new EventEmitter(); + @Output() readonly modeChanged: EventEmitter = + new EventEmitter(); + @Output() readonly openedChanged: EventEmitter = + new EventEmitter(); + @Output() + readonly positionChanged: EventEmitter = + new EventEmitter(); + @ViewChild('navigationContent') private _navigationContentEl: ElementRef; + + activeAsideItemId: string | null = null; + onCollapsableItemCollapsed: ReplaySubject = + new ReplaySubject(1); + onCollapsableItemExpanded: ReplaySubject = + new ReplaySubject(1); + onRefreshed: ReplaySubject = new ReplaySubject(1); + private _animationsEnabled: boolean = false; + private _asideOverlay: HTMLElement; + private readonly _handleAsideOverlayClick: any; + private readonly _handleOverlayClick: any; + private _hovered: boolean = false; + private _mutationObserver: MutationObserver; + private _overlay: HTMLElement; + private _player: AnimationPlayer; + private _scrollStrategy: ScrollStrategy = + this._scrollStrategyOptions.block(); + private _fuseScrollbarDirectives!: QueryList; + private _fuseScrollbarDirectivesSubscription: Subscription; + private _unsubscribeAll: Subject = new Subject(); + + /** + * Constructor + */ + constructor() { + this._handleAsideOverlayClick = (): void => { + this.closeAside(); + }; + this._handleOverlayClick = (): void => { + this.close(); + }; + } + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Host binding for component classes + */ + @HostBinding('class') get classList(): any { + /* eslint-disable @typescript-eslint/naming-convention */ + return { + 'fuse-vertical-navigation-animations-enabled': + this._animationsEnabled, + [`fuse-vertical-navigation-appearance-${this.appearance}`]: true, + 'fuse-vertical-navigation-hover': this._hovered, + 'fuse-vertical-navigation-inner': this.inner, + 'fuse-vertical-navigation-mode-over': this.mode === 'over', + 'fuse-vertical-navigation-mode-side': this.mode === 'side', + 'fuse-vertical-navigation-opened': this.opened, + 'fuse-vertical-navigation-position-left': this.position === 'left', + 'fuse-vertical-navigation-position-right': + this.position === 'right', + }; + /* eslint-enable @typescript-eslint/naming-convention */ + } + + /** + * Host binding for component inline styles + */ + @HostBinding('style') get styleList(): any { + return { + visibility: this.opened ? 'visible' : 'hidden', + }; + } + + /** + * Setter for fuseScrollbarDirectives + */ + @ViewChildren(FuseScrollbarDirective) + set fuseScrollbarDirectives( + fuseScrollbarDirectives: QueryList + ) { + // Store the directives + this._fuseScrollbarDirectives = fuseScrollbarDirectives; + + // Return if there are no directives + if (fuseScrollbarDirectives.length === 0) { + return; + } + + // Unsubscribe the previous subscriptions + if (this._fuseScrollbarDirectivesSubscription) { + this._fuseScrollbarDirectivesSubscription.unsubscribe(); + } + + // Update the scrollbars on collapsable items' collapse/expand + this._fuseScrollbarDirectivesSubscription = merge( + this.onCollapsableItemCollapsed, + this.onCollapsableItemExpanded + ) + .pipe(takeUntil(this._unsubscribeAll), delay(250)) + .subscribe(() => { + // Loop through the scrollbars and update them + fuseScrollbarDirectives.forEach((fuseScrollbarDirective) => { + fuseScrollbarDirective.update(); + }); + }); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Decorated methods + // ----------------------------------------------------------------------------------------------------- + + /** + * On mouseenter + * + * @private + */ + @HostListener('mouseenter') + private _onMouseenter(): void { + // Enable the animations + this._enableAnimations(); + + // Set the hovered + this._hovered = true; + } + + /** + * On mouseleave + * + * @private + */ + @HostListener('mouseleave') + private _onMouseleave(): void { + // Enable the animations + this._enableAnimations(); + + // Set the hovered + this._hovered = false; + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On changes + * + * @param changes + */ + ngOnChanges(changes: SimpleChanges): void { + // Appearance + if ('appearance' in changes) { + // Execute the observable + this.appearanceChanged.next(changes.appearance.currentValue); + } + + // Inner + if ('inner' in changes) { + // Coerce the value to a boolean + this.inner = coerceBooleanProperty(changes.inner.currentValue); + } + + // Mode + if ('mode' in changes) { + // Get the previous and current values + const currentMode = changes.mode.currentValue; + const previousMode = changes.mode.previousValue; + + // Disable the animations + this._disableAnimations(); + + // If the mode changes: 'over -> side' + if (previousMode === 'over' && currentMode === 'side') { + // Hide the overlay + this._hideOverlay(); + } + + // If the mode changes: 'side -> over' + if (previousMode === 'side' && currentMode === 'over') { + // Close the aside + this.closeAside(); + + // If the navigation is opened + if (this.opened) { + // Show the overlay + this._showOverlay(); + } + } + + // Execute the observable + this.modeChanged.next(currentMode); + + // Enable the animations after a delay + // The delay must be bigger than the current transition-duration + // to make sure nothing will be animated while the mode changing + setTimeout(() => { + this._enableAnimations(); + }, 500); + } + + // Navigation + if ('navigation' in changes) { + // Mark for check + this._changeDetectorRef.markForCheck(); + } + + // Opened + if ('opened' in changes) { + // Coerce the value to a boolean + this.opened = coerceBooleanProperty(changes.opened.currentValue); + + // Open/close the navigation + this._toggleOpened(this.opened); + } + + // Position + if ('position' in changes) { + // Execute the observable + this.positionChanged.next(changes.position.currentValue); + } + + // Transparent overlay + if ('transparentOverlay' in changes) { + // Coerce the value to a boolean + this.transparentOverlay = coerceBooleanProperty( + changes.transparentOverlay.currentValue + ); + } + } + + /** + * On init + */ + ngOnInit(): void { + // Make sure the name input is not an empty string + if (this.name === '') { + this.name = this._fuseUtilsService.randomId(); + } + + // Register the navigation component + this._fuseNavigationService.registerComponent(this.name, this); + + // Subscribe to the 'NavigationEnd' event + this._router.events + .pipe( + filter((event) => event instanceof NavigationEnd), + takeUntil(this._unsubscribeAll) + ) + .subscribe(() => { + // If the mode is 'over' and the navigation is opened... + if (this.mode === 'over' && this.opened) { + // Close the navigation + this.close(); + } + + // If the mode is 'side' and the aside is active... + if (this.mode === 'side' && this.activeAsideItemId) { + // Close the aside + this.closeAside(); + } + }); + } + + /** + * After view init + */ + ngAfterViewInit(): void { + // Fix for Firefox. + // + // Because 'position: sticky' doesn't work correctly inside a 'position: fixed' parent, + // adding the '.cdk-global-scrollblock' to the html element breaks the navigation's position. + // This fixes the problem by reading the 'top' value from the html element and adding it as a + // 'marginTop' to the navigation itself. + this._mutationObserver = new MutationObserver((mutations) => { + mutations.forEach((mutation) => { + const mutationTarget = mutation.target as HTMLElement; + if (mutation.attributeName === 'class') { + if ( + mutationTarget.classList.contains( + 'cdk-global-scrollblock' + ) + ) { + const top = parseInt(mutationTarget.style.top, 10); + this._renderer2.setStyle( + this._elementRef.nativeElement, + 'margin-top', + `${Math.abs(top)}px` + ); + } else { + this._renderer2.setStyle( + this._elementRef.nativeElement, + 'margin-top', + null + ); + } + } + }); + }); + this._mutationObserver.observe(this._document.documentElement, { + attributes: true, + attributeFilter: ['class'], + }); + + setTimeout(() => { + // Return if 'navigation content' element does not exist + if (!this._navigationContentEl) { + return; + } + + // If 'navigation content' element doesn't have + // perfect scrollbar activated on it... + if ( + !this._navigationContentEl.nativeElement.classList.contains( + 'ps' + ) + ) { + // Find the active item + const activeItem = + this._navigationContentEl.nativeElement.querySelector( + '.fuse-vertical-navigation-item-active' + ); + + // If the active item exists, scroll it into view + if (activeItem) { + activeItem.scrollIntoView(); + } + } + // Otherwise + else { + // Go through all the scrollbar directives + this._fuseScrollbarDirectives.forEach( + (fuseScrollbarDirective) => { + // Skip if not enabled + if (!fuseScrollbarDirective.isEnabled()) { + return; + } + + // Scroll to the active element + fuseScrollbarDirective.scrollToElement( + '.fuse-vertical-navigation-item-active', + -120, + true + ); + } + ); + } + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Disconnect the mutation observer + this._mutationObserver.disconnect(); + + // Forcefully close the navigation and aside in case they are opened + this.close(); + this.closeAside(); + + // Deregister the navigation component from the registry + this._fuseNavigationService.deregisterComponent(this.name); + + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Refresh the component to apply the changes + */ + refresh(): void { + // Mark for check + this._changeDetectorRef.markForCheck(); + + // Execute the observable + this.onRefreshed.next(true); + } + + /** + * Open the navigation + */ + open(): void { + // Return if the navigation is already open + if (this.opened) { + return; + } + + // Set the opened + this._toggleOpened(true); + } + + /** + * Close the navigation + */ + close(): void { + // Return if the navigation is already closed + if (!this.opened) { + return; + } + + // Close the aside + this.closeAside(); + + // Set the opened + this._toggleOpened(false); + } + + /** + * Toggle the navigation + */ + toggle(): void { + // Toggle + if (this.opened) { + this.close(); + } else { + this.open(); + } + } + + /** + * Open the aside + * + * @param item + */ + openAside(item: FuseNavigationItem): void { + // Return if the item is disabled + if (item.disabled || !item.id) { + return; + } + + // Open + this.activeAsideItemId = item.id; + + // Show the aside overlay + this._showAsideOverlay(); + + // Mark for check + this._changeDetectorRef.markForCheck(); + } + + /** + * Close the aside + */ + closeAside(): void { + // Close + this.activeAsideItemId = null; + + // Hide the aside overlay + this._hideAsideOverlay(); + + // Mark for check + this._changeDetectorRef.markForCheck(); + } + + /** + * Toggle the aside + * + * @param item + */ + toggleAside(item: FuseNavigationItem): void { + // Toggle + if (this.activeAsideItemId === item.id) { + this.closeAside(); + } else { + this.openAside(item); + } + } + + /** + * Track by function for ngFor loops + * + * @param index + * @param item + */ + trackByFn(index: number, item: any): any { + return item.id || index; + } + + // ----------------------------------------------------------------------------------------------------- + // @ Private methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Enable the animations + * + * @private + */ + private _enableAnimations(): void { + // Return if the animations are already enabled + if (this._animationsEnabled) { + return; + } + + // Enable the animations + this._animationsEnabled = true; + } + + /** + * Disable the animations + * + * @private + */ + private _disableAnimations(): void { + // Return if the animations are already disabled + if (!this._animationsEnabled) { + return; + } + + // Disable the animations + this._animationsEnabled = false; + } + + /** + * Show the overlay + * + * @private + */ + private _showOverlay(): void { + // Return if there is already an overlay + if (this._asideOverlay) { + return; + } + + // Create the overlay element + this._overlay = this._renderer2.createElement('div'); + + // Add a class to the overlay element + this._overlay.classList.add('fuse-vertical-navigation-overlay'); + + // Add a class depending on the transparentOverlay option + if (this.transparentOverlay) { + this._overlay.classList.add( + 'fuse-vertical-navigation-overlay-transparent' + ); + } + + // Append the overlay to the parent of the navigation + this._renderer2.appendChild( + this._elementRef.nativeElement.parentElement, + this._overlay + ); + + // Enable block scroll strategy + this._scrollStrategy.enable(); + + // Create the enter animation and attach it to the player + this._player = this._animationBuilder + .build([ + animate( + '300ms cubic-bezier(0.25, 0.8, 0.25, 1)', + style({ opacity: 1 }) + ), + ]) + .create(this._overlay); + + // Play the animation + this._player.play(); + + // Add an event listener to the overlay + this._overlay.addEventListener('click', this._handleOverlayClick); + } + + /** + * Hide the overlay + * + * @private + */ + private _hideOverlay(): void { + if (!this._overlay) { + return; + } + + // Create the leave animation and attach it to the player + this._player = this._animationBuilder + .build([ + animate( + '300ms cubic-bezier(0.25, 0.8, 0.25, 1)', + style({ opacity: 0 }) + ), + ]) + .create(this._overlay); + + // Play the animation + this._player.play(); + + // Once the animation is done... + this._player.onDone(() => { + // If the overlay still exists... + if (this._overlay) { + // Remove the event listener + this._overlay.removeEventListener( + 'click', + this._handleOverlayClick + ); + + // Remove the overlay + this._overlay.parentNode.removeChild(this._overlay); + this._overlay = null; + } + + // Disable block scroll strategy + this._scrollStrategy.disable(); + }); + } + + /** + * Show the aside overlay + * + * @private + */ + private _showAsideOverlay(): void { + // Return if there is already an overlay + if (this._asideOverlay) { + return; + } + + // Create the aside overlay element + this._asideOverlay = this._renderer2.createElement('div'); + + // Add a class to the aside overlay element + this._asideOverlay.classList.add( + 'fuse-vertical-navigation-aside-overlay' + ); + + // Append the aside overlay to the parent of the navigation + this._renderer2.appendChild( + this._elementRef.nativeElement.parentElement, + this._asideOverlay + ); + + // Create the enter animation and attach it to the player + this._player = this._animationBuilder + .build([ + animate( + '300ms cubic-bezier(0.25, 0.8, 0.25, 1)', + style({ opacity: 1 }) + ), + ]) + .create(this._asideOverlay); + + // Play the animation + this._player.play(); + + // Add an event listener to the aside overlay + this._asideOverlay.addEventListener( + 'click', + this._handleAsideOverlayClick + ); + } + + /** + * Hide the aside overlay + * + * @private + */ + private _hideAsideOverlay(): void { + if (!this._asideOverlay) { + return; + } + + // Create the leave animation and attach it to the player + this._player = this._animationBuilder + .build([ + animate( + '300ms cubic-bezier(0.25, 0.8, 0.25, 1)', + style({ opacity: 0 }) + ), + ]) + .create(this._asideOverlay); + + // Play the animation + this._player.play(); + + // Once the animation is done... + this._player.onDone(() => { + // If the aside overlay still exists... + if (this._asideOverlay) { + // Remove the event listener + this._asideOverlay.removeEventListener( + 'click', + this._handleAsideOverlayClick + ); + + // Remove the aside overlay + this._asideOverlay.parentNode.removeChild(this._asideOverlay); + this._asideOverlay = null; + } + }); + } + + /** + * Open/close the navigation + * + * @param open + * @private + */ + private _toggleOpened(open: boolean): void { + // Set the opened + this.opened = open; + + // Enable the animations + this._enableAnimations(); + + // If the navigation opened, and the mode + // is 'over', show the overlay + if (this.mode === 'over') { + if (this.opened) { + this._showOverlay(); + } else { + this._hideOverlay(); + } + } + + // Execute the observable + this.openedChanged.next(open); + } +} diff --git a/frontend/src/@fuse/directives/scroll-reset/index.ts b/frontend/src/@fuse/directives/scroll-reset/index.ts new file mode 100644 index 00000000..f1f563bc --- /dev/null +++ b/frontend/src/@fuse/directives/scroll-reset/index.ts @@ -0,0 +1 @@ +export * from '@fuse/directives/scroll-reset/public-api'; diff --git a/frontend/src/@fuse/directives/scroll-reset/public-api.ts b/frontend/src/@fuse/directives/scroll-reset/public-api.ts new file mode 100644 index 00000000..a5192a0c --- /dev/null +++ b/frontend/src/@fuse/directives/scroll-reset/public-api.ts @@ -0,0 +1 @@ +export * from '@fuse/directives/scroll-reset/scroll-reset.directive'; diff --git a/frontend/src/@fuse/directives/scroll-reset/scroll-reset.directive.ts b/frontend/src/@fuse/directives/scroll-reset/scroll-reset.directive.ts new file mode 100644 index 00000000..f06ec64d --- /dev/null +++ b/frontend/src/@fuse/directives/scroll-reset/scroll-reset.directive.ts @@ -0,0 +1,50 @@ +import { + Directive, + ElementRef, + inject, + OnDestroy, + OnInit, +} from '@angular/core'; +import { NavigationEnd, Router } from '@angular/router'; +import { filter, Subject, takeUntil } from 'rxjs'; + +@Directive({ + selector: '[fuseScrollReset]', + exportAs: 'fuseScrollReset', + standalone: true, +}) +export class FuseScrollResetDirective implements OnInit, OnDestroy { + private _elementRef = inject(ElementRef); + private _router = inject(Router); + + private _unsubscribeAll: Subject = new Subject(); + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Subscribe to NavigationEnd event + this._router.events + .pipe( + filter((event) => event instanceof NavigationEnd), + takeUntil(this._unsubscribeAll) + ) + .subscribe(() => { + // Reset the element's scroll position to the top + this._elementRef.nativeElement.scrollTop = 0; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } +} diff --git a/frontend/src/@fuse/directives/scrollbar/index.ts b/frontend/src/@fuse/directives/scrollbar/index.ts new file mode 100644 index 00000000..9aba5806 --- /dev/null +++ b/frontend/src/@fuse/directives/scrollbar/index.ts @@ -0,0 +1 @@ +export * from '@fuse/directives/scrollbar/public-api'; diff --git a/frontend/src/@fuse/directives/scrollbar/public-api.ts b/frontend/src/@fuse/directives/scrollbar/public-api.ts new file mode 100644 index 00000000..5e80e778 --- /dev/null +++ b/frontend/src/@fuse/directives/scrollbar/public-api.ts @@ -0,0 +1 @@ +export * from '@fuse/directives/scrollbar/scrollbar.directive'; diff --git a/frontend/src/@fuse/directives/scrollbar/scrollbar.directive.ts b/frontend/src/@fuse/directives/scrollbar/scrollbar.directive.ts new file mode 100644 index 00000000..e8c57cc4 --- /dev/null +++ b/frontend/src/@fuse/directives/scrollbar/scrollbar.directive.ts @@ -0,0 +1,446 @@ +import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion'; +import { Platform } from '@angular/cdk/platform'; +import { + Directive, + ElementRef, + Input, + OnChanges, + OnDestroy, + OnInit, + SimpleChanges, + inject, +} from '@angular/core'; +import { + ScrollbarGeometry, + ScrollbarPosition, +} from '@fuse/directives/scrollbar/scrollbar.types'; +import { merge } from 'lodash-es'; +import PerfectScrollbar from 'perfect-scrollbar'; +import { Subject, debounceTime, fromEvent, takeUntil } from 'rxjs'; + +/** + * Wrapper directive for the Perfect Scrollbar: https://github.com/mdbootstrap/perfect-scrollbar + */ +@Directive({ + selector: '[fuseScrollbar]', + exportAs: 'fuseScrollbar', + standalone: true, +}) +export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy { + /* eslint-disable @typescript-eslint/naming-convention */ + static ngAcceptInputType_fuseScrollbar: BooleanInput; + /* eslint-enable @typescript-eslint/naming-convention */ + + private _elementRef = inject(ElementRef); + private _platform = inject(Platform); + + @Input() fuseScrollbar: boolean = true; + @Input() fuseScrollbarOptions: PerfectScrollbar.Options; + + private _animation: number; + private _options: PerfectScrollbar.Options; + private _ps: PerfectScrollbar; + private _unsubscribeAll: Subject = new Subject(); + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Getter for _elementRef + */ + get elementRef(): ElementRef { + return this._elementRef; + } + + /** + * Getter for _ps + */ + get ps(): PerfectScrollbar | null { + return this._ps; + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On changes + * + * @param changes + */ + ngOnChanges(changes: SimpleChanges): void { + // Enabled + if ('fuseScrollbar' in changes) { + // Interpret empty string as 'true' + this.fuseScrollbar = coerceBooleanProperty( + changes.fuseScrollbar.currentValue + ); + + // If enabled, init the directive + if (this.fuseScrollbar) { + this._init(); + } + // Otherwise destroy it + else { + this._destroy(); + } + } + + // Scrollbar options + if ('fuseScrollbarOptions' in changes) { + // Merge the options + this._options = merge( + {}, + this._options, + changes.fuseScrollbarOptions.currentValue + ); + + // Return if not initialized + if (!this._ps) { + return; + } + + // Destroy and re-init the PerfectScrollbar to update its options + setTimeout(() => { + this._destroy(); + }); + + setTimeout(() => { + this._init(); + }); + } + } + + /** + * On init + */ + ngOnInit(): void { + // Subscribe to window resize event + fromEvent(window, 'resize') + .pipe(takeUntil(this._unsubscribeAll), debounceTime(150)) + .subscribe(() => { + // Update the PerfectScrollbar + this.update(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + this._destroy(); + + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Is enabled + */ + isEnabled(): boolean { + return this.fuseScrollbar; + } + + /** + * Update the scrollbar + */ + update(): void { + // Return if not initialized + if (!this._ps) { + return; + } + + // Update the PerfectScrollbar + this._ps.update(); + } + + /** + * Destroy the scrollbar + */ + destroy(): void { + this.ngOnDestroy(); + } + + /** + * Returns the geometry of the scrollable element + * + * @param prefix + */ + geometry(prefix: string = 'scroll'): ScrollbarGeometry { + return new ScrollbarGeometry( + this._elementRef.nativeElement[prefix + 'Left'], + this._elementRef.nativeElement[prefix + 'Top'], + this._elementRef.nativeElement[prefix + 'Width'], + this._elementRef.nativeElement[prefix + 'Height'] + ); + } + + /** + * Returns the position of the scrollable element + * + * @param absolute + */ + position(absolute: boolean = false): ScrollbarPosition { + let scrollbarPosition; + + if (!absolute && this._ps) { + scrollbarPosition = new ScrollbarPosition( + this._ps.reach.x || 0, + this._ps.reach.y || 0 + ); + } else { + scrollbarPosition = new ScrollbarPosition( + this._elementRef.nativeElement.scrollLeft, + this._elementRef.nativeElement.scrollTop + ); + } + + return scrollbarPosition; + } + + /** + * Scroll to + * + * @param x + * @param y + * @param speed + */ + scrollTo(x: number, y?: number, speed?: number): void { + if (y == null && speed == null) { + this.animateScrolling('scrollTop', x, speed); + } else { + if (x != null) { + this.animateScrolling('scrollLeft', x, speed); + } + + if (y != null) { + this.animateScrolling('scrollTop', y, speed); + } + } + } + + /** + * Scroll to X + * + * @param x + * @param speed + */ + scrollToX(x: number, speed?: number): void { + this.animateScrolling('scrollLeft', x, speed); + } + + /** + * Scroll to Y + * + * @param y + * @param speed + */ + scrollToY(y: number, speed?: number): void { + this.animateScrolling('scrollTop', y, speed); + } + + /** + * Scroll to top + * + * @param offset + * @param speed + */ + scrollToTop(offset: number = 0, speed?: number): void { + this.animateScrolling('scrollTop', offset, speed); + } + + /** + * Scroll to bottom + * + * @param offset + * @param speed + */ + scrollToBottom(offset: number = 0, speed?: number): void { + const top = + this._elementRef.nativeElement.scrollHeight - + this._elementRef.nativeElement.clientHeight; + this.animateScrolling('scrollTop', top - offset, speed); + } + + /** + * Scroll to left + * + * @param offset + * @param speed + */ + scrollToLeft(offset: number = 0, speed?: number): void { + this.animateScrolling('scrollLeft', offset, speed); + } + + /** + * Scroll to right + * + * @param offset + * @param speed + */ + scrollToRight(offset: number = 0, speed?: number): void { + const left = + this._elementRef.nativeElement.scrollWidth - + this._elementRef.nativeElement.clientWidth; + this.animateScrolling('scrollLeft', left - offset, speed); + } + + /** + * Scroll to element + * + * @param qs + * @param offset + * @param ignoreVisible If true, scrollToElement won't happen if element is already inside the current viewport + * @param speed + */ + scrollToElement( + qs: string, + offset: number = 0, + ignoreVisible: boolean = false, + speed?: number + ): void { + const element = this._elementRef.nativeElement.querySelector(qs); + + if (!element) { + return; + } + + const elementPos = element.getBoundingClientRect(); + const scrollerPos = + this._elementRef.nativeElement.getBoundingClientRect(); + + if (this._elementRef.nativeElement.classList.contains('ps--active-x')) { + if ( + ignoreVisible && + elementPos.right <= scrollerPos.right - Math.abs(offset) + ) { + return; + } + + const currentPos = this._elementRef.nativeElement['scrollLeft']; + const position = elementPos.left - scrollerPos.left + currentPos; + + this.animateScrolling('scrollLeft', position + offset, speed); + } + + if (this._elementRef.nativeElement.classList.contains('ps--active-y')) { + if ( + ignoreVisible && + elementPos.bottom <= scrollerPos.bottom - Math.abs(offset) + ) { + return; + } + + const currentPos = this._elementRef.nativeElement['scrollTop']; + const position = elementPos.top - scrollerPos.top + currentPos; + + this.animateScrolling('scrollTop', position + offset, speed); + } + } + + /** + * Animate scrolling + * + * @param target + * @param value + * @param speed + */ + animateScrolling(target: string, value: number, speed?: number): void { + if (this._animation) { + window.cancelAnimationFrame(this._animation); + this._animation = null; + } + + if (!speed || typeof window === 'undefined') { + this._elementRef.nativeElement[target] = value; + } else if (value !== this._elementRef.nativeElement[target]) { + let newValue = 0; + let scrollCount = 0; + + let oldTimestamp = performance.now(); + let oldValue = this._elementRef.nativeElement[target]; + + const cosParameter = (oldValue - value) / 2; + + const step = (newTimestamp: number): void => { + scrollCount += + Math.PI / (speed / (newTimestamp - oldTimestamp)); + newValue = Math.round( + value + cosParameter + cosParameter * Math.cos(scrollCount) + ); + + // Only continue animation if scroll position has not changed + if (this._elementRef.nativeElement[target] === oldValue) { + if (scrollCount >= Math.PI) { + this.animateScrolling(target, value, 0); + } else { + this._elementRef.nativeElement[target] = newValue; + + // On a zoomed out page the resulting offset may differ + oldValue = this._elementRef.nativeElement[target]; + oldTimestamp = newTimestamp; + + this._animation = window.requestAnimationFrame(step); + } + } + }; + + window.requestAnimationFrame(step); + } + } + + // ----------------------------------------------------------------------------------------------------- + // @ Private methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Initialize + * + * @private + */ + private _init(): void { + // Return if already initialized + if (this._ps) { + return; + } + + // Return if on mobile or not on browser + if ( + this._platform.ANDROID || + this._platform.IOS || + !this._platform.isBrowser + ) { + this.fuseScrollbar = false; + return; + } + + // Initialize the PerfectScrollbar + this._ps = new PerfectScrollbar(this._elementRef.nativeElement, { + ...this._options, + }); + } + + /** + * Destroy + * + * @private + */ + private _destroy(): void { + // Return if not initialized + if (!this._ps) { + return; + } + + // Destroy the PerfectScrollbar + this._ps.destroy(); + + // Clean up + this._ps = null; + } +} diff --git a/frontend/src/@fuse/directives/scrollbar/scrollbar.types.ts b/frontend/src/@fuse/directives/scrollbar/scrollbar.types.ts new file mode 100644 index 00000000..aee42cde --- /dev/null +++ b/frontend/src/@fuse/directives/scrollbar/scrollbar.types.ts @@ -0,0 +1,24 @@ +export class ScrollbarGeometry { + public x: number; + public y: number; + + public w: number; + public h: number; + + constructor(x: number, y: number, w: number, h: number) { + this.x = x; + this.y = y; + this.w = w; + this.h = h; + } +} + +export class ScrollbarPosition { + public x: number | 'start' | 'end'; + public y: number | 'start' | 'end'; + + constructor(x: number | 'start' | 'end', y: number | 'start' | 'end') { + this.x = x; + this.y = y; + } +} diff --git a/frontend/src/@fuse/fuse.provider.ts b/frontend/src/@fuse/fuse.provider.ts new file mode 100644 index 00000000..d9c40515 --- /dev/null +++ b/frontend/src/@fuse/fuse.provider.ts @@ -0,0 +1,121 @@ +import { provideHttpClient, withInterceptors } from '@angular/common/http'; +import { + APP_INITIALIZER, + ENVIRONMENT_INITIALIZER, + EnvironmentProviders, + Provider, + importProvidersFrom, + inject, +} from '@angular/core'; +import { MATERIAL_SANITY_CHECKS } from '@angular/material/core'; +import { MatDialogModule } from '@angular/material/dialog'; +import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field'; +import { + FUSE_MOCK_API_DEFAULT_DELAY, + mockApiInterceptor, +} from '@fuse/lib/mock-api'; +import { FuseConfig } from '@fuse/services/config'; +import { FUSE_CONFIG } from '@fuse/services/config/config.constants'; +import { FuseConfirmationService } from '@fuse/services/confirmation'; +import { + FuseLoadingService, + fuseLoadingInterceptor, +} from '@fuse/services/loading'; +import { FuseMediaWatcherService } from '@fuse/services/media-watcher'; +import { FusePlatformService } from '@fuse/services/platform'; +import { FuseSplashScreenService } from '@fuse/services/splash-screen'; +import { FuseUtilsService } from '@fuse/services/utils'; + +export type FuseProviderConfig = { + mockApi?: { + delay?: number; + services?: any[]; + }; + fuse?: FuseConfig; +}; + +/** + * Fuse provider + */ +export const provideFuse = ( + config: FuseProviderConfig +): Array => { + // Base providers + const providers: Array = [ + { + // Disable 'theme' sanity check + provide: MATERIAL_SANITY_CHECKS, + useValue: { + doctype: true, + theme: false, + version: true, + }, + }, + { + // Use the 'fill' appearance on Angular Material form fields by default + provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, + useValue: { + appearance: 'fill', + }, + }, + { + provide: FUSE_MOCK_API_DEFAULT_DELAY, + useValue: config?.mockApi?.delay ?? 0, + }, + { + provide: FUSE_CONFIG, + useValue: config?.fuse ?? {}, + }, + + importProvidersFrom(MatDialogModule), + { + provide: ENVIRONMENT_INITIALIZER, + useValue: () => inject(FuseConfirmationService), + multi: true, + }, + + provideHttpClient(withInterceptors([fuseLoadingInterceptor])), + { + provide: ENVIRONMENT_INITIALIZER, + useValue: () => inject(FuseLoadingService), + multi: true, + }, + + { + provide: ENVIRONMENT_INITIALIZER, + useValue: () => inject(FuseMediaWatcherService), + multi: true, + }, + { + provide: ENVIRONMENT_INITIALIZER, + useValue: () => inject(FusePlatformService), + multi: true, + }, + { + provide: ENVIRONMENT_INITIALIZER, + useValue: () => inject(FuseSplashScreenService), + multi: true, + }, + { + provide: ENVIRONMENT_INITIALIZER, + useValue: () => inject(FuseUtilsService), + multi: true, + }, + ]; + + // Mock Api services + if (config?.mockApi?.services) { + providers.push( + provideHttpClient(withInterceptors([mockApiInterceptor])), + { + provide: APP_INITIALIZER, + deps: [...config.mockApi.services], + useFactory: () => (): any => null, + multi: true, + } + ); + } + + // Return the providers + return providers; +}; diff --git a/frontend/src/@fuse/index.ts b/frontend/src/@fuse/index.ts new file mode 100644 index 00000000..31e43335 --- /dev/null +++ b/frontend/src/@fuse/index.ts @@ -0,0 +1 @@ +export * from './fuse.provider'; diff --git a/frontend/src/@fuse/lib/mock-api/index.ts b/frontend/src/@fuse/lib/mock-api/index.ts new file mode 100644 index 00000000..121e0f72 --- /dev/null +++ b/frontend/src/@fuse/lib/mock-api/index.ts @@ -0,0 +1 @@ +export * from '@fuse/lib/mock-api/public-api'; diff --git a/frontend/src/@fuse/lib/mock-api/mock-api.constants.ts b/frontend/src/@fuse/lib/mock-api/mock-api.constants.ts new file mode 100644 index 00000000..5036ec65 --- /dev/null +++ b/frontend/src/@fuse/lib/mock-api/mock-api.constants.ts @@ -0,0 +1,5 @@ +import { InjectionToken } from '@angular/core'; + +export const FUSE_MOCK_API_DEFAULT_DELAY = new InjectionToken( + 'FUSE_MOCK_API_DEFAULT_DELAY' +); diff --git a/frontend/src/@fuse/lib/mock-api/mock-api.interceptor.ts b/frontend/src/@fuse/lib/mock-api/mock-api.interceptor.ts new file mode 100644 index 00000000..a5ce544c --- /dev/null +++ b/frontend/src/@fuse/lib/mock-api/mock-api.interceptor.ts @@ -0,0 +1,82 @@ +import { + HttpErrorResponse, + HttpEvent, + HttpHandlerFn, + HttpRequest, + HttpResponse, +} from '@angular/common/http'; +import { inject } from '@angular/core'; +import { FUSE_MOCK_API_DEFAULT_DELAY } from '@fuse/lib/mock-api/mock-api.constants'; +import { FuseMockApiService } from '@fuse/lib/mock-api/mock-api.service'; +import { Observable, delay, of, switchMap, throwError } from 'rxjs'; + +export const mockApiInterceptor = ( + request: HttpRequest, + next: HttpHandlerFn +): Observable> => { + const defaultDelay = inject(FUSE_MOCK_API_DEFAULT_DELAY); + const fuseMockApiService = inject(FuseMockApiService); + + // Try to get the request handler + const { handler, urlParams } = fuseMockApiService.findHandler( + request.method.toUpperCase(), + request.url + ); + + // Pass through if the request handler does not exist + if (!handler) { + return next(request); + } + + // Set the intercepted request on the handler + handler.request = request; + + // Set the url params on the handler + handler.urlParams = urlParams; + + // Subscribe to the response function observable + return handler.response.pipe( + delay(handler.delay ?? defaultDelay ?? 0), + switchMap((response) => { + // If there is no response data, + // throw an error response + if (!response) { + response = new HttpErrorResponse({ + error: 'NOT FOUND', + status: 404, + statusText: 'NOT FOUND', + }); + + return throwError(response); + } + + // Parse the response data + const data = { + status: response[0], + body: response[1], + }; + + // If the status code is in between 200 and 300, + // return a success response + if (data.status >= 200 && data.status < 300) { + response = new HttpResponse({ + body: data.body, + status: data.status, + statusText: 'OK', + }); + + return of(response); + } + + // For other status codes, + // throw an error response + response = new HttpErrorResponse({ + error: data.body.error, + status: data.status, + statusText: 'ERROR', + }); + + return throwError(response); + }) + ); +}; diff --git a/frontend/src/@fuse/lib/mock-api/mock-api.request-handler.ts b/frontend/src/@fuse/lib/mock-api/mock-api.request-handler.ts new file mode 100644 index 00000000..08807f43 --- /dev/null +++ b/frontend/src/@fuse/lib/mock-api/mock-api.request-handler.ts @@ -0,0 +1,87 @@ +import { HttpRequest } from '@angular/common/http'; +import { FuseMockApiReplyCallback } from '@fuse/lib/mock-api/mock-api.types'; +import { Observable, of, take, throwError } from 'rxjs'; + +export class FuseMockApiHandler { + request!: HttpRequest; + urlParams!: { [key: string]: string }; + + // Private + private _reply: FuseMockApiReplyCallback = undefined; + private _replyCount = 0; + private _replied = 0; + + /** + * Constructor + */ + constructor( + public url: string, + public delay?: number + ) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Getter for response callback + */ + get response(): Observable { + // If the execution limit has been reached, throw an error + if (this._replyCount > 0 && this._replyCount <= this._replied) { + return throwError('Execution limit has been reached!'); + } + + // If the response callback has not been set, throw an error + if (!this._reply) { + return throwError('Response callback function does not exist!'); + } + + // If the request has not been set, throw an error + if (!this.request) { + return throwError('Request does not exist!'); + } + + // Increase the replied count + this._replied++; + + // Execute the reply callback + const replyResult = this._reply({ + request: this.request, + urlParams: this.urlParams, + }); + + // If the result of the reply callback is an observable... + if (replyResult instanceof Observable) { + // Return the result as it is + return replyResult.pipe(take(1)); + } + + // Otherwise, return the result as an observable + return of(replyResult).pipe(take(1)); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Reply + * + * @param callback + */ + reply(callback: FuseMockApiReplyCallback): void { + // Store the reply + this._reply = callback; + } + + /** + * Reply count + * + * @param count + */ + replyCount(count: number): void { + // Store the reply count + this._replyCount = count; + } +} diff --git a/frontend/src/@fuse/lib/mock-api/mock-api.service.ts b/frontend/src/@fuse/lib/mock-api/mock-api.service.ts new file mode 100644 index 00000000..ee5caee5 --- /dev/null +++ b/frontend/src/@fuse/lib/mock-api/mock-api.service.ts @@ -0,0 +1,201 @@ +import { Injectable } from '@angular/core'; +import { FuseMockApiHandler } from '@fuse/lib/mock-api/mock-api.request-handler'; +import { FuseMockApiMethods } from '@fuse/lib/mock-api/mock-api.types'; +import { compact, fromPairs } from 'lodash-es'; + +@Injectable({ providedIn: 'root' }) +export class FuseMockApiService { + private _handlers: { [key: string]: Map } = { + get: new Map(), + post: new Map(), + patch: new Map(), + delete: new Map(), + put: new Map(), + head: new Map(), + jsonp: new Map(), + options: new Map(), + }; + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Find the handler from the service + * with the given method and url + * + * @param method + * @param url + */ + findHandler( + method: string, + url: string + ): { + handler: FuseMockApiHandler | undefined; + urlParams: { [key: string]: string }; + } { + // Prepare the return object + const matchingHandler: { + handler: FuseMockApiHandler | undefined; + urlParams: { [key: string]: string }; + } = { + handler: undefined, + urlParams: {}, + }; + + // Split the url + const urlParts = url.split('/'); + + // Get all related request handlers + const handlers = this._handlers[method.toLowerCase()]; + + // Iterate through the handlers + handlers.forEach((handler, handlerUrl) => { + // Skip if there is already a matching handler + if (matchingHandler.handler) { + return; + } + + // Split the handler url + const handlerUrlParts = handlerUrl.split('/'); + + // Skip if the lengths of the urls we are comparing are not the same + if (urlParts.length !== handlerUrlParts.length) { + return; + } + + // Compare + const matches = handlerUrlParts.every( + (handlerUrlPart, index) => + handlerUrlPart === urlParts[index] || + handlerUrlPart.startsWith(':') + ); + + // If there is a match... + if (matches) { + // Assign the matching handler + matchingHandler.handler = handler; + + // Extract and assign the parameters + matchingHandler.urlParams = fromPairs( + compact( + handlerUrlParts.map((handlerUrlPart, index) => + handlerUrlPart.startsWith(':') + ? [handlerUrlPart.substring(1), urlParts[index]] + : undefined + ) + ) + ); + } + }); + + return matchingHandler; + } + + /** + * Register GET request handler + * + * @param url - URL address of the mocked API endpoint + * @param delay - Delay of the response in milliseconds + */ + onGet(url: string, delay?: number): FuseMockApiHandler { + return this._registerHandler('get', url, delay); + } + + /** + * Register POST request handler + * + * @param url - URL address of the mocked API endpoint + * @param delay - Delay of the response in milliseconds + */ + onPost(url: string, delay?: number): FuseMockApiHandler { + return this._registerHandler('post', url, delay); + } + + /** + * Register PATCH request handler + * + * @param url - URL address of the mocked API endpoint + * @param delay - Delay of the response in milliseconds + */ + onPatch(url: string, delay?: number): FuseMockApiHandler { + return this._registerHandler('patch', url, delay); + } + + /** + * Register DELETE request handler + * + * @param url - URL address of the mocked API endpoint + * @param delay - Delay of the response in milliseconds + */ + onDelete(url: string, delay?: number): FuseMockApiHandler { + return this._registerHandler('delete', url, delay); + } + + /** + * Register PUT request handler + * + * @param url - URL address of the mocked API endpoint + * @param delay - Delay of the response in milliseconds + */ + onPut(url: string, delay?: number): FuseMockApiHandler { + return this._registerHandler('put', url, delay); + } + + /** + * Register HEAD request handler + * + * @param url - URL address of the mocked API endpoint + * @param delay - Delay of the response in milliseconds + */ + onHead(url: string, delay?: number): FuseMockApiHandler { + return this._registerHandler('head', url, delay); + } + + /** + * Register JSONP request handler + * + * @param url - URL address of the mocked API endpoint + * @param delay - Delay of the response in milliseconds + */ + onJsonp(url: string, delay?: number): FuseMockApiHandler { + return this._registerHandler('jsonp', url, delay); + } + + /** + * Register OPTIONS request handler + * + * @param url - URL address of the mocked API endpoint + * @param delay - Delay of the response in milliseconds + */ + onOptions(url: string, delay?: number): FuseMockApiHandler { + return this._registerHandler('options', url, delay); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Private methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Register and return a new instance of the handler + * + * @param method + * @param url + * @param delay + * @private + */ + private _registerHandler( + method: FuseMockApiMethods, + url: string, + delay?: number + ): FuseMockApiHandler { + // Create a new instance of FuseMockApiRequestHandler + const fuseMockHttp = new FuseMockApiHandler(url, delay); + + // Store the handler to access it from the interceptor + this._handlers[method].set(url, fuseMockHttp); + + // Return the instance + return fuseMockHttp; + } +} diff --git a/frontend/src/@fuse/lib/mock-api/mock-api.types.ts b/frontend/src/@fuse/lib/mock-api/mock-api.types.ts new file mode 100644 index 00000000..a7154e3b --- /dev/null +++ b/frontend/src/@fuse/lib/mock-api/mock-api.types.ts @@ -0,0 +1,19 @@ +import { HttpRequest } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +export type FuseMockApiReplyCallback = + | ((data: { + request: HttpRequest; + urlParams: { [key: string]: string }; + }) => [number, string | any] | Observable) + | undefined; + +export type FuseMockApiMethods = + | 'get' + | 'post' + | 'patch' + | 'delete' + | 'put' + | 'head' + | 'jsonp' + | 'options'; diff --git a/frontend/src/@fuse/lib/mock-api/mock-api.utils.ts b/frontend/src/@fuse/lib/mock-api/mock-api.utils.ts new file mode 100644 index 00000000..8194f60e --- /dev/null +++ b/frontend/src/@fuse/lib/mock-api/mock-api.utils.ts @@ -0,0 +1,30 @@ +export class FuseMockApiUtils { + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Generate a globally unique id + */ + static guid(): string { + /* eslint-disable */ + + let d = new Date().getTime(); + + // Use high-precision timer if available + if ( + typeof performance !== 'undefined' && + typeof performance.now === 'function' + ) { + d += performance.now(); + } + + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { + const r = (d + Math.random() * 16) % 16 | 0; + d = Math.floor(d / 16); + return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16); + }); + + /* eslint-enable */ + } +} diff --git a/frontend/src/@fuse/lib/mock-api/public-api.ts b/frontend/src/@fuse/lib/mock-api/public-api.ts new file mode 100644 index 00000000..4fc941dc --- /dev/null +++ b/frontend/src/@fuse/lib/mock-api/public-api.ts @@ -0,0 +1,5 @@ +export * from '@fuse/lib/mock-api/mock-api.constants'; +export * from '@fuse/lib/mock-api/mock-api.interceptor'; +export * from '@fuse/lib/mock-api/mock-api.service'; +export * from '@fuse/lib/mock-api/mock-api.types'; +export * from '@fuse/lib/mock-api/mock-api.utils'; diff --git a/frontend/src/@fuse/pipes/find-by-key/find-by-key.pipe.ts b/frontend/src/@fuse/pipes/find-by-key/find-by-key.pipe.ts new file mode 100644 index 00000000..978e5043 --- /dev/null +++ b/frontend/src/@fuse/pipes/find-by-key/find-by-key.pipe.ts @@ -0,0 +1,30 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +/** + * Finds an object from given source using the given key - value pairs + */ +@Pipe({ + name: 'fuseFindByKey', + pure: false, + standalone: true, +}) +export class FuseFindByKeyPipe implements PipeTransform { + /** + * Transform + * + * @param value A string or an array of strings to find from source + * @param key Key of the object property to look for + * @param source Array of objects to find from + */ + transform(value: string | string[], key: string, source: any[]): any { + // If the given value is an array of strings... + if (Array.isArray(value)) { + return value.map((item) => + source.find((sourceItem) => sourceItem[key] === item) + ); + } + + // If the value is a string... + return source.find((sourceItem) => sourceItem[key] === value); + } +} diff --git a/frontend/src/@fuse/pipes/find-by-key/index.ts b/frontend/src/@fuse/pipes/find-by-key/index.ts new file mode 100644 index 00000000..61efac02 --- /dev/null +++ b/frontend/src/@fuse/pipes/find-by-key/index.ts @@ -0,0 +1 @@ +export * from '@fuse/pipes/find-by-key/public-api'; diff --git a/frontend/src/@fuse/pipes/find-by-key/public-api.ts b/frontend/src/@fuse/pipes/find-by-key/public-api.ts new file mode 100644 index 00000000..c62e68d8 --- /dev/null +++ b/frontend/src/@fuse/pipes/find-by-key/public-api.ts @@ -0,0 +1,2 @@ +export * from '@fuse/pipes/find-by-key/find-by-key.module'; +export * from '@fuse/pipes/find-by-key/find-by-key.pipe'; diff --git a/frontend/src/@fuse/services/config/config.constants.ts b/frontend/src/@fuse/services/config/config.constants.ts new file mode 100644 index 00000000..fd82bb02 --- /dev/null +++ b/frontend/src/@fuse/services/config/config.constants.ts @@ -0,0 +1,3 @@ +import { InjectionToken } from '@angular/core'; + +export const FUSE_CONFIG = new InjectionToken('FUSE_APP_CONFIG'); diff --git a/frontend/src/@fuse/services/config/config.service.ts b/frontend/src/@fuse/services/config/config.service.ts new file mode 100644 index 00000000..6350f5c5 --- /dev/null +++ b/frontend/src/@fuse/services/config/config.service.ts @@ -0,0 +1,41 @@ +import { inject, Injectable } from '@angular/core'; +import { FUSE_CONFIG } from '@fuse/services/config/config.constants'; +import { merge } from 'lodash-es'; +import { BehaviorSubject, Observable } from 'rxjs'; + +@Injectable({ providedIn: 'root' }) +export class FuseConfigService { + private _config = new BehaviorSubject(inject(FUSE_CONFIG)); + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Setter & getter for config + */ + set config(value: any) { + // Merge the new config over to the current config + const config = merge({}, this._config.getValue(), value); + + // Execute the observable + this._config.next(config); + } + + // eslint-disable-next-line @typescript-eslint/member-ordering + get config$(): Observable { + return this._config.asObservable(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Resets the config to the default + */ + reset(): void { + // Set the config + this._config.next(this.config); + } +} diff --git a/frontend/src/@fuse/services/config/config.types.ts b/frontend/src/@fuse/services/config/config.types.ts new file mode 100644 index 00000000..5a557b69 --- /dev/null +++ b/frontend/src/@fuse/services/config/config.types.ts @@ -0,0 +1,17 @@ +// Types +export type Scheme = 'auto' | 'dark' | 'light'; +export type Screens = { [key: string]: string }; +export type Theme = 'theme-default' | string; +export type Themes = { id: string; name: string }[]; + +/** + * AppConfig interface. Update this interface to strictly type your config + * object. + */ +export interface FuseConfig { + layout: string; + scheme: Scheme; + screens: Screens; + theme: Theme; + themes: Themes; +} diff --git a/frontend/src/@fuse/services/config/index.ts b/frontend/src/@fuse/services/config/index.ts new file mode 100644 index 00000000..0563cafe --- /dev/null +++ b/frontend/src/@fuse/services/config/index.ts @@ -0,0 +1 @@ +export * from '@fuse/services/config/public-api'; diff --git a/frontend/src/@fuse/services/config/public-api.ts b/frontend/src/@fuse/services/config/public-api.ts new file mode 100644 index 00000000..cb38bdc7 --- /dev/null +++ b/frontend/src/@fuse/services/config/public-api.ts @@ -0,0 +1,2 @@ +export * from '@fuse/services/config/config.service'; +export * from '@fuse/services/config/config.types'; diff --git a/frontend/src/@fuse/services/confirmation/confirmation.service.ts b/frontend/src/@fuse/services/confirmation/confirmation.service.ts new file mode 100644 index 00000000..68d6fda7 --- /dev/null +++ b/frontend/src/@fuse/services/confirmation/confirmation.service.ts @@ -0,0 +1,50 @@ +import { inject, Injectable } from '@angular/core'; +import { MatDialog, MatDialogRef } from '@angular/material/dialog'; +import { FuseConfirmationConfig } from '@fuse/services/confirmation/confirmation.types'; +import { FuseConfirmationDialogComponent } from '@fuse/services/confirmation/dialog/dialog.component'; +import { merge } from 'lodash-es'; + +@Injectable({ providedIn: 'root' }) +export class FuseConfirmationService { + private _matDialog: MatDialog = inject(MatDialog); + private _defaultConfig: FuseConfirmationConfig = { + title: 'Confirm action', + message: 'Are you sure you want to confirm this action?', + icon: { + show: true, + name: 'heroicons_outline:exclamation-triangle', + color: 'warn', + }, + actions: { + confirm: { + show: true, + label: 'Confirm', + color: 'warn', + }, + cancel: { + show: true, + label: 'Cancel', + }, + }, + dismissible: false, + }; + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + open( + config: FuseConfirmationConfig = {} + ): MatDialogRef { + // Merge the user config with the default config + const userConfig = merge({}, this._defaultConfig, config); + + // Open the dialog + return this._matDialog.open(FuseConfirmationDialogComponent, { + autoFocus: false, + disableClose: !userConfig.dismissible, + data: userConfig, + panelClass: 'fuse-confirmation-dialog-panel', + }); + } +} diff --git a/frontend/src/@fuse/services/confirmation/confirmation.types.ts b/frontend/src/@fuse/services/confirmation/confirmation.types.ts new file mode 100644 index 00000000..1ffd6301 --- /dev/null +++ b/frontend/src/@fuse/services/confirmation/confirmation.types.ts @@ -0,0 +1,29 @@ +export interface FuseConfirmationConfig { + title?: string; + message?: string; + icon?: { + show?: boolean; + name?: string; + color?: + | 'primary' + | 'accent' + | 'warn' + | 'basic' + | 'info' + | 'success' + | 'warning' + | 'error'; + }; + actions?: { + confirm?: { + show?: boolean; + label?: string; + color?: 'primary' | 'accent' | 'warn'; + }; + cancel?: { + show?: boolean; + label?: string; + }; + }; + dismissible?: boolean; +} diff --git a/frontend/src/@fuse/services/confirmation/dialog/dialog.component.html b/frontend/src/@fuse/services/confirmation/dialog/dialog.component.html new file mode 100644 index 00000000..36e0d1c6 --- /dev/null +++ b/frontend/src/@fuse/services/confirmation/dialog/dialog.component.html @@ -0,0 +1,95 @@ +
+ + @if (data.dismissible) { +
+ +
+ } + + +
+ + @if (data.icon.show) { +
+ +
+ } + + @if (data.title || data.message) { +
+ + @if (data.title) { +
+ } + + + @if (data.message) { +
+ } +
+ } +
+ + + @if (data.actions.confirm.show || data.actions.cancel.show) { +
+ + @if (data.actions.cancel.show) { + + } + + + @if (data.actions.confirm.show) { + + } +
+ } +
diff --git a/frontend/src/@fuse/services/confirmation/dialog/dialog.component.ts b/frontend/src/@fuse/services/confirmation/dialog/dialog.component.ts new file mode 100644 index 00000000..f9604d9a --- /dev/null +++ b/frontend/src/@fuse/services/confirmation/dialog/dialog.component.ts @@ -0,0 +1,32 @@ +import { NgClass } from '@angular/common'; +import { Component, ViewEncapsulation, inject } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; +import { MatIconModule } from '@angular/material/icon'; +import { FuseConfirmationConfig } from '@fuse/services/confirmation/confirmation.types'; + +@Component({ + selector: 'fuse-confirmation-dialog', + templateUrl: './dialog.component.html', + styles: [ + ` + .fuse-confirmation-dialog-panel { + @screen md { + @apply w-128; + } + + .mat-mdc-dialog-container { + .mat-mdc-dialog-surface { + padding: 0 !important; + } + } + } + `, + ], + encapsulation: ViewEncapsulation.None, + standalone: true, + imports: [MatButtonModule, MatDialogModule, MatIconModule, NgClass], +}) +export class FuseConfirmationDialogComponent { + data: FuseConfirmationConfig = inject(MAT_DIALOG_DATA); +} diff --git a/frontend/src/@fuse/services/confirmation/index.ts b/frontend/src/@fuse/services/confirmation/index.ts new file mode 100644 index 00000000..f6f2fee1 --- /dev/null +++ b/frontend/src/@fuse/services/confirmation/index.ts @@ -0,0 +1 @@ +export * from '@fuse/services/confirmation/public-api'; diff --git a/frontend/src/@fuse/services/confirmation/public-api.ts b/frontend/src/@fuse/services/confirmation/public-api.ts new file mode 100644 index 00000000..91367332 --- /dev/null +++ b/frontend/src/@fuse/services/confirmation/public-api.ts @@ -0,0 +1,2 @@ +export * from '@fuse/services/confirmation/confirmation.service'; +export * from '@fuse/services/confirmation/confirmation.types'; diff --git a/frontend/src/@fuse/services/loading/index.ts b/frontend/src/@fuse/services/loading/index.ts new file mode 100644 index 00000000..deaac8da --- /dev/null +++ b/frontend/src/@fuse/services/loading/index.ts @@ -0,0 +1 @@ +export * from '@fuse/services/loading/public-api'; diff --git a/frontend/src/@fuse/services/loading/loading.interceptor.ts b/frontend/src/@fuse/services/loading/loading.interceptor.ts new file mode 100644 index 00000000..41280118 --- /dev/null +++ b/frontend/src/@fuse/services/loading/loading.interceptor.ts @@ -0,0 +1,31 @@ +import { HttpEvent, HttpHandlerFn, HttpRequest } from '@angular/common/http'; +import { inject } from '@angular/core'; +import { FuseLoadingService } from '@fuse/services/loading/loading.service'; +import { Observable, finalize, take } from 'rxjs'; + +export const fuseLoadingInterceptor = ( + req: HttpRequest, + next: HttpHandlerFn +): Observable> => { + const fuseLoadingService = inject(FuseLoadingService); + let handleRequestsAutomatically = false; + + fuseLoadingService.auto$.pipe(take(1)).subscribe((value) => { + handleRequestsAutomatically = value; + }); + + // If the Auto mode is turned off, do nothing + if (!handleRequestsAutomatically) { + return next(req); + } + + // Set the loading status to true + fuseLoadingService._setLoadingStatus(true, req.url); + + return next(req).pipe( + finalize(() => { + // Set the status to false if there are any errors or the request is completed + fuseLoadingService._setLoadingStatus(false, req.url); + }) + ); +}; diff --git a/frontend/src/@fuse/services/loading/loading.service.ts b/frontend/src/@fuse/services/loading/loading.service.ts new file mode 100644 index 00000000..1bb45409 --- /dev/null +++ b/frontend/src/@fuse/services/loading/loading.service.ts @@ -0,0 +1,126 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject, Observable } from 'rxjs'; + +@Injectable({ providedIn: 'root' }) +export class FuseLoadingService { + private _auto$: BehaviorSubject = new BehaviorSubject( + true + ); + private _mode$: BehaviorSubject<'determinate' | 'indeterminate'> = + new BehaviorSubject<'determinate' | 'indeterminate'>('indeterminate'); + private _progress$: BehaviorSubject = new BehaviorSubject< + number | null + >(0); + private _show$: BehaviorSubject = new BehaviorSubject( + false + ); + private _urlMap: Map = new Map(); + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Getter for auto mode + */ + get auto$(): Observable { + return this._auto$.asObservable(); + } + + /** + * Getter for mode + */ + get mode$(): Observable<'determinate' | 'indeterminate'> { + return this._mode$.asObservable(); + } + + /** + * Getter for progress + */ + get progress$(): Observable { + return this._progress$.asObservable(); + } + + /** + * Getter for show + */ + get show$(): Observable { + return this._show$.asObservable(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Show the loading bar + */ + show(): void { + this._show$.next(true); + } + + /** + * Hide the loading bar + */ + hide(): void { + this._show$.next(false); + } + + /** + * Set the auto mode + * + * @param value + */ + setAutoMode(value: boolean): void { + this._auto$.next(value); + } + + /** + * Set the mode + * + * @param value + */ + setMode(value: 'determinate' | 'indeterminate'): void { + this._mode$.next(value); + } + + /** + * Set the progress of the bar manually + * + * @param value + */ + setProgress(value: number): void { + if (value < 0 || value > 100) { + console.error('Progress value must be between 0 and 100!'); + return; + } + + this._progress$.next(value); + } + + /** + * Sets the loading status on the given url + * + * @param status + * @param url + */ + _setLoadingStatus(status: boolean, url: string): void { + // Return if the url was not provided + if (!url) { + console.error('The request URL must be provided!'); + return; + } + + if (status === true) { + this._urlMap.set(url, status); + this._show$.next(true); + } else if (status === false && this._urlMap.has(url)) { + this._urlMap.delete(url); + } + + // Only set the status to 'false' if all outgoing requests are completed + if (this._urlMap.size === 0) { + this._show$.next(false); + } + } +} diff --git a/frontend/src/@fuse/services/loading/public-api.ts b/frontend/src/@fuse/services/loading/public-api.ts new file mode 100644 index 00000000..51ab7e19 --- /dev/null +++ b/frontend/src/@fuse/services/loading/public-api.ts @@ -0,0 +1,2 @@ +export * from '@fuse/services/loading/loading.interceptor'; +export * from '@fuse/services/loading/loading.service'; diff --git a/frontend/src/@fuse/services/media-watcher/index.ts b/frontend/src/@fuse/services/media-watcher/index.ts new file mode 100644 index 00000000..b2dad0cb --- /dev/null +++ b/frontend/src/@fuse/services/media-watcher/index.ts @@ -0,0 +1 @@ +export * from '@fuse/services/media-watcher/public-api'; diff --git a/frontend/src/@fuse/services/media-watcher/media-watcher.service.ts b/frontend/src/@fuse/services/media-watcher/media-watcher.service.ts new file mode 100644 index 00000000..fe5b4071 --- /dev/null +++ b/frontend/src/@fuse/services/media-watcher/media-watcher.service.ts @@ -0,0 +1,100 @@ +import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout'; +import { Injectable, inject } from '@angular/core'; +import { FuseConfigService } from '@fuse/services/config'; +import { fromPairs } from 'lodash-es'; +import { Observable, ReplaySubject, map, switchMap } from 'rxjs'; + +@Injectable({ providedIn: 'root' }) +export class FuseMediaWatcherService { + private _breakpointObserver = inject(BreakpointObserver); + private _fuseConfigService = inject(FuseConfigService); + + private _onMediaChange: ReplaySubject<{ + matchingAliases: string[]; + matchingQueries: any; + }> = new ReplaySubject<{ matchingAliases: string[]; matchingQueries: any }>( + 1 + ); + + /** + * Constructor + */ + constructor() { + this._fuseConfigService.config$ + .pipe( + map((config) => + fromPairs( + Object.entries(config.screens).map( + ([alias, screen]) => [ + alias, + `(min-width: ${screen})`, + ] + ) + ) + ), + switchMap((screens) => + this._breakpointObserver + .observe(Object.values(screens)) + .pipe( + map((state) => { + // Prepare the observable values and set their defaults + const matchingAliases: string[] = []; + const matchingQueries: any = {}; + + // Get the matching breakpoints and use them to fill the subject + const matchingBreakpoints = + Object.entries(state.breakpoints).filter( + ([query, matches]) => matches + ) ?? []; + for (const [query] of matchingBreakpoints) { + // Find the alias of the matching query + const matchingAlias = Object.entries( + screens + ).find(([alias, q]) => q === query)[0]; + + // Add the matching query to the observable values + if (matchingAlias) { + matchingAliases.push(matchingAlias); + matchingQueries[matchingAlias] = query; + } + } + + // Execute the observable + this._onMediaChange.next({ + matchingAliases, + matchingQueries, + }); + }) + ) + ) + ) + .subscribe(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Getter for _onMediaChange + */ + get onMediaChange$(): Observable<{ + matchingAliases: string[]; + matchingQueries: any; + }> { + return this._onMediaChange.asObservable(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * On media query change + * + * @param query + */ + onMediaQueryChange$(query: string | string[]): Observable { + return this._breakpointObserver.observe(query); + } +} diff --git a/frontend/src/@fuse/services/media-watcher/public-api.ts b/frontend/src/@fuse/services/media-watcher/public-api.ts new file mode 100644 index 00000000..88a928b2 --- /dev/null +++ b/frontend/src/@fuse/services/media-watcher/public-api.ts @@ -0,0 +1 @@ +export * from '@fuse/services/media-watcher/media-watcher.service'; diff --git a/frontend/src/@fuse/services/platform/index.ts b/frontend/src/@fuse/services/platform/index.ts new file mode 100644 index 00000000..2eea68d4 --- /dev/null +++ b/frontend/src/@fuse/services/platform/index.ts @@ -0,0 +1 @@ +export * from '@fuse/services/platform/public-api'; diff --git a/frontend/src/@fuse/services/platform/platform.service.ts b/frontend/src/@fuse/services/platform/platform.service.ts new file mode 100644 index 00000000..7addc1de --- /dev/null +++ b/frontend/src/@fuse/services/platform/platform.service.ts @@ -0,0 +1,49 @@ +import { Platform } from '@angular/cdk/platform'; +import { inject, Injectable } from '@angular/core'; + +@Injectable({ providedIn: 'root' }) +export class FusePlatformService { + private _platform = inject(Platform); + + osName = 'os-unknown'; + + /** + * Constructor + */ + constructor() { + // If the platform is not a browser, return immediately + if (!this._platform.isBrowser) { + return; + } + + // Windows + if (navigator.userAgent.includes('Win')) { + this.osName = 'os-windows'; + } + + // Mac OS + if (navigator.userAgent.includes('Mac')) { + this.osName = 'os-mac'; + } + + // Unix + if (navigator.userAgent.includes('X11')) { + this.osName = 'os-unix'; + } + + // Linux + if (navigator.userAgent.includes('Linux')) { + this.osName = 'os-linux'; + } + + // iOS + if (this._platform.IOS) { + this.osName = 'os-ios'; + } + + // Android + if (this._platform.ANDROID) { + this.osName = 'os-android'; + } + } +} diff --git a/frontend/src/@fuse/services/platform/public-api.ts b/frontend/src/@fuse/services/platform/public-api.ts new file mode 100644 index 00000000..05d0e32e --- /dev/null +++ b/frontend/src/@fuse/services/platform/public-api.ts @@ -0,0 +1 @@ +export * from '@fuse/services/platform/platform.service'; diff --git a/frontend/src/@fuse/services/splash-screen/index.ts b/frontend/src/@fuse/services/splash-screen/index.ts new file mode 100644 index 00000000..79ce6e49 --- /dev/null +++ b/frontend/src/@fuse/services/splash-screen/index.ts @@ -0,0 +1 @@ +export * from '@fuse/services/splash-screen/public-api'; diff --git a/frontend/src/@fuse/services/splash-screen/public-api.ts b/frontend/src/@fuse/services/splash-screen/public-api.ts new file mode 100644 index 00000000..195e3023 --- /dev/null +++ b/frontend/src/@fuse/services/splash-screen/public-api.ts @@ -0,0 +1 @@ +export * from '@fuse/services/splash-screen/splash-screen.service'; diff --git a/frontend/src/@fuse/services/splash-screen/splash-screen.service.ts b/frontend/src/@fuse/services/splash-screen/splash-screen.service.ts new file mode 100644 index 00000000..5d3cb1b8 --- /dev/null +++ b/frontend/src/@fuse/services/splash-screen/splash-screen.service.ts @@ -0,0 +1,43 @@ +import { DOCUMENT } from '@angular/common'; +import { inject, Injectable } from '@angular/core'; +import { NavigationEnd, Router } from '@angular/router'; +import { filter, take } from 'rxjs'; + +@Injectable({ providedIn: 'root' }) +export class FuseSplashScreenService { + private _document = inject(DOCUMENT); + private _router = inject(Router); + + /** + * Constructor + */ + constructor() { + // Hide it on the first NavigationEnd event + this._router.events + .pipe( + filter((event) => event instanceof NavigationEnd), + take(1) + ) + .subscribe(() => { + this.hide(); + }); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Show the splash screen + */ + show(): void { + this._document.body.classList.remove('fuse-splash-screen-hidden'); + } + + /** + * Hide the splash screen + */ + hide(): void { + this._document.body.classList.add('fuse-splash-screen-hidden'); + } +} diff --git a/frontend/src/@fuse/services/utils/index.ts b/frontend/src/@fuse/services/utils/index.ts new file mode 100644 index 00000000..a507e7ff --- /dev/null +++ b/frontend/src/@fuse/services/utils/index.ts @@ -0,0 +1 @@ +export * from '@fuse/services/utils/public-api'; diff --git a/frontend/src/@fuse/services/utils/public-api.ts b/frontend/src/@fuse/services/utils/public-api.ts new file mode 100644 index 00000000..60af22f2 --- /dev/null +++ b/frontend/src/@fuse/services/utils/public-api.ts @@ -0,0 +1 @@ +export * from '@fuse/services/utils/utils.service'; diff --git a/frontend/src/@fuse/services/utils/utils.service.ts b/frontend/src/@fuse/services/utils/utils.service.ts new file mode 100644 index 00000000..d7f37c78 --- /dev/null +++ b/frontend/src/@fuse/services/utils/utils.service.ts @@ -0,0 +1,54 @@ +import { Injectable } from '@angular/core'; +import { IsActiveMatchOptions } from '@angular/router'; + +@Injectable({ providedIn: 'root' }) +export class FuseUtilsService { + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Get the equivalent "IsActiveMatchOptions" options for "exact = true". + */ + get exactMatchOptions(): IsActiveMatchOptions { + return { + paths: 'exact', + fragment: 'ignored', + matrixParams: 'ignored', + queryParams: 'exact', + }; + } + + /** + * Get the equivalent "IsActiveMatchOptions" options for "exact = false". + */ + get subsetMatchOptions(): IsActiveMatchOptions { + return { + paths: 'subset', + fragment: 'ignored', + matrixParams: 'ignored', + queryParams: 'subset', + }; + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Generates a random id + * + * @param length + */ + randomId(length: number = 10): string { + const chars = + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + let name = ''; + + for (let i = 0; i < 10; i++) { + name += chars.charAt(Math.floor(Math.random() * chars.length)); + } + + return name; + } +} diff --git a/frontend/src/@fuse/styles/components/example-viewer.scss b/frontend/src/@fuse/styles/components/example-viewer.scss new file mode 100644 index 00000000..43e3d806 --- /dev/null +++ b/frontend/src/@fuse/styles/components/example-viewer.scss @@ -0,0 +1,44 @@ +/* ----------------------------------------------------------------------------------------------------- */ +/* @ Example viewer +/* ----------------------------------------------------------------------------------------------------- */ +.example-viewer { + display: flex; + flex-direction: column; + margin: 32px 0; + overflow: hidden; + @apply bg-card rounded-2xl shadow; + + .title { + display: flex; + align-items: center; + justify-content: space-between; + height: 88px; + min-height: 88px; + max-height: 88px; + padding: 0 40px; + + h6 { + font-weight: 700; + } + + .controls { + display: flex; + align-items: center; + + > * + * { + margin-left: 8px; + } + } + } + + mat-tab-group { + .mat-tab-body-content { + .fuse-highlight { + pre { + margin: 0; + border-radius: 0; + } + } + } + } +} diff --git a/frontend/src/@fuse/styles/components/input.scss b/frontend/src/@fuse/styles/components/input.scss new file mode 100644 index 00000000..391b400d --- /dev/null +++ b/frontend/src/@fuse/styles/components/input.scss @@ -0,0 +1,43 @@ +input, +textarea { + background: transparent; + + /* Placeholder color */ + &::placeholder { + @apply text-hint; + } + + &::-moz-placeholder { + @apply text-hint; + } + + &::-webkit-input-placeholder { + @apply text-hint; + } + + &:-ms-input-placeholder { + @apply text-hint; + } + + /* Autofill color fix */ + &:-webkit-autofill, + &:-webkit-autofill:hover, + &:-webkit-autofill:focus, + &:-webkit-autofill:active { + -webkit-background-clip: text; + transition: background-color 5000s !important; + } + + .dark & { + &:-webkit-autofill, + &:-webkit-autofill:hover, + &:-webkit-autofill:focus, + &:-webkit-autofill:active { + -webkit-text-fill-color: rgba(255, 255, 255, 0.87); + } + } + + [data-autocompleted] { + background-color: transparent !important; + } +} diff --git a/frontend/src/@fuse/styles/main.scss b/frontend/src/@fuse/styles/main.scss new file mode 100644 index 00000000..41f69c2f --- /dev/null +++ b/frontend/src/@fuse/styles/main.scss @@ -0,0 +1,9 @@ +/* 1. Components */ +@use 'components/example-viewer'; +@use 'components/input'; + +/* 2. Overrides */ +@use 'overrides/angular-material'; +@use 'overrides/highlightjs'; +@use 'overrides/perfect-scrollbar'; +@use 'overrides/quill'; diff --git a/frontend/src/@fuse/styles/overrides/angular-material.scss b/frontend/src/@fuse/styles/overrides/angular-material.scss new file mode 100644 index 00000000..4faf8751 --- /dev/null +++ b/frontend/src/@fuse/styles/overrides/angular-material.scss @@ -0,0 +1,1283 @@ +/* -------------------------------------------------------------------------- */ +/* @ Overlay +/* -------------------------------------------------------------------------- */ +.fuse-backdrop-on-mobile { + @apply bg-black bg-opacity-60 sm:bg-transparent #{'!important'}; +} + +/* -------------------------------------------------------------------------- */ +/* @ Font smoothing +/* -------------------------------------------------------------------------- */ +*[class*='mat-'], +*[class*='mat-mdc-'] { + -webkit-font-smoothing: auto !important; + -moz-osx-font-smoothing: auto !important; + + * { + -webkit-font-smoothing: auto !important; + -moz-osx-font-smoothing: auto !important; + } +} + +/* -------------------------------------------------------------------------- */ +/* @ Accordion +/* -------------------------------------------------------------------------- */ +.mat-accordion { + .mat-expansion-panel { + margin-bottom: 24px; + border-radius: 8px !important; + transition: box-shadow 225ms cubic-bezier(0.4, 0, 0.2, 1); + @apply shadow #{'!important'}; + + &:last-child { + margin-bottom: 0; + } + + &.mat-expanded, + &:hover { + @apply shadow-lg #{'!important'}; + } + + &:not(.mat-expanded) { + .mat-expansion-panel-header { + &:not([aria-disabled='true']) { + &.cdk-keyboard-focused, + &.cdk-program-focused, + &:hover { + background: transparent !important; + } + } + } + } + + .mat-expansion-panel-header { + font-size: 14px; + + &[aria-disabled='true'] { + .mat-expansion-panel-header-description { + margin-right: 28px; + } + } + + .mat-expansion-indicator { + display: inline-flex; + align-items: center; + justify-content: center; + width: 12px; + height: 12px; + + /* Do not override the border color of the expansion panel indicator */ + &:after { + border-color: currentColor !important; + } + } + } + + .mat-expansion-panel-body { + @apply text-secondary #{'!important'}; + } + } +} + +/* -------------------------------------------------------------------------- */ +/* @ Buttons +/* -------------------------------------------------------------------------- */ +.mat-mdc-button, +.mat-mdc-raised-button, +.mat-mdc-outlined-button, +.mat-mdc-unelevated-button, +.mat-mdc-icon-button, +.mat-mdc-fab, +.mat-mdc-mini-fab { + height: 40px; + min-height: 40px; + max-height: 40px; + line-height: 1 !important; + + /* Large button */ + &.fuse-mat-button-large { + height: 48px; + min-height: 48px; + max-height: 48px; + } + + /* Lower the icon opacity on disabled buttons */ + &[disabled='true'] { + .mat-icon { + opacity: 0.38 !important; + } + } +} + +/* Icon buttons */ +.mat-mdc-icon-button { + display: inline-flex !important; + align-items: center; + justify-content: center; + width: 40px !important; + padding: 0 !important; + + svg, + img { + height: auto !important; + } +} + +/* FAB buttons */ +.mat-mdc-fab { + max-height: 56px; + border-radius: 16px !important; + + &:not(.mdc-fab--extended) .mdc-fab__ripple { + border-radius: 16px !important; + } +} + +/* Mini FAB buttons */ +.mat-mdc-mini-fab { + border-radius: 12px !important; + + &:not(.mdc-fab--extended) .mdc-fab__ripple { + border-radius: 12px !important; + } +} + +/* Rounded design */ +.mat-mdc-button, +.mat-mdc-raised-button, +.mat-mdc-outlined-button, +.mat-mdc-unelevated-button { + padding: 0 20px !important; + border-radius: 9999px !important; +} + +/* Fix the alignment of icons when used within buttons */ +.mat-mdc-button, +.mat-mdc-raised-button, +.mat-mdc-outlined-button, +.mat-mdc-unelevated-button { + & > .mat-icon { + margin-left: 0 !important; + margin-right: 0 !important; + } +} + +/* Adjust the color of mat-progress-spinner when used within buttons */ +.mat-mdc-button, +.mat-mdc-raised-button, +.mat-mdc-outlined-button, +.mat-mdc-unelevated-button, +.mat-mdc-icon-button, +.mat-mdc-fab, +.mat-mdc-mini-fab { + .mat-mdc-progress-spinner { + .mdc-circular-progress__indeterminate-container { + circle { + stroke: currentColor !important; + animation-duration: 6000ms; + } + } + } +} + +/* Adjust the focus, ripple and icon colors of colored background buttons */ +.mat-mdc-raised-button, +.mat-mdc-unelevated-button, +.mat-mdc-fab, +.mat-mdc-mini-fab { + --mat-mdc-button-persistent-ripple-color: theme( + 'colors.gray[400]' + ) !important; + --mat-mdc-button-ripple-color: rgba(0, 0, 0, 0.1) !important; + + .dark & { + --mat-mdc-button-persistent-ripple-color: theme( + 'colors.black' + ) !important; + --mat-mdc-button-ripple-color: rgba(0, 0, 0, 0.1) !important; + } + + .mat-icon { + color: currentColor !important; + } + + .mat-ripple-element { + @apply bg-black/10 #{'!important'}; + } +} + +/* Color the icons of transparent background buttons */ +.mat-mdc-button, +.mat-mdc-icon-button, +.mat-mdc-outlined-button { + &:not([disabled='true']) { + /* Apply primary color */ + &.mat-primary { + .mat-icon { + @apply text-primary #{'!important'}; + } + } + + /* Apply accent color */ + &.mat-accent { + .mat-icon { + @apply text-accent #{'!important'}; + } + } + + /* Apply warn color */ + &.mat-warn { + .mat-icon { + @apply text-warn #{'!important'}; + } + } + } +} + +/* Adjust the border color of outlined buttons */ +.mat-mdc-outlined-button { + /* Not disabled */ + &:not([disabled='true']) { + @apply border-gray-300 dark:border-gray-500 #{'!important'}; + } + + /* Disabled */ + &[disabled='true'] { + @apply border-gray-300/70 dark:border-gray-600 #{'!important'}; + } +} + +/* Don't wrap the button label text */ +.mdc-button { + .mdc-button__label { + white-space: nowrap; + } +} + +/* -------------------------------------------------------------------------- */ +/* @ Button Toggle +/* -------------------------------------------------------------------------- */ +.mat-button-toggle-group { + border: none !important; + @apply space-x-1; + + &.mat-button-toggle-group-appearance-standard { + .mat-button-toggle + .mat-button-toggle { + background-clip: padding-box; + } + } + + .mat-button-toggle { + border-radius: 9999px; + overflow: hidden; + border: none !important; + font-weight: 500; + + &.mat-button-toggle-checked { + .mat-button-toggle-label-content { + @apply text-default #{'!important'}; + } + } + + .mat-button-toggle-label-content { + padding: 0 20px; + line-height: 40px !important; + @apply text-secondary; + } + } +} + +/* -------------------------------------------------------------------------- */ +/* @ Checkbox +/* -------------------------------------------------------------------------- */ +.mat-mdc-checkbox { + display: inline-flex !important; + + .mdc-form-field { + padding-right: 12px; + } +} + +.mdc-checkbox__native-control { + opacity: 0 !important; +} + +/* -------------------------------------------------------------------------- */ +/* @ Chip +/* -------------------------------------------------------------------------- */ +.mat-mdc-chip { + font-weight: 500 !important; +} + +/* -------------------------------------------------------------------------- */ +/* @ Dialog +/* -------------------------------------------------------------------------- */ +.mat-mdc-dialog-container { + .mdc-dialog__surface { + border-radius: 16px !important; + padding: 24px; + } +} + +/* -------------------------------------------------------------------------- */ +/* @ Drawer +/* -------------------------------------------------------------------------- */ +.mat-drawer-backdrop.mat-drawer-shown { + background-color: rgba(0, 0, 0, 0.6) !important; +} + +/* -------------------------------------------------------------------------- */ +/* @ Form fields +/* -------------------------------------------------------------------------- */ + +/* "fill" appearance */ +.mat-mdc-form-field.mat-form-field-appearance-fill { + /* Disabled */ + &.mat-form-field-disabled { + opacity: 0.7 !important; + } + + /* Invalid */ + &.mat-form-field-invalid { + /* Border color */ + .mat-mdc-text-field-wrapper { + @apply border-warn dark:border-warn #{'!important'}; + } + + /* Select */ + .mat-mdc-select { + /* Placeholder color */ + .mat-mdc-select-placeholder { + @apply text-warn #{'!important'}; + } + } + } + + /* Hover */ + &:hover { + .mat-mdc-form-field-focus-overlay { + opacity: 0 !important; + } + } + + /* Focused */ + &.mat-focused { + .mat-mdc-form-field-focus-overlay { + opacity: 0 !important; + } + } + + /* Focused and valid fields */ + &.mat-focused:not(.mat-form-field-invalid) { + /* Border color */ + .mat-mdc-text-field-wrapper { + @apply border-primary dark:border-primary #{'!important'}; + } + } + + /* Remove the default arrow for native select */ + &.mat-mdc-form-field-type-mat-native-select { + .mat-mdc-form-field-infix { + select { + top: auto; + margin-top: 0; + margin-bottom: 0; + padding-top: 0; + padding-right: 18px; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%2364748B' viewBox='0 0 24 24'%3E%3Cpath d='M7 10l5 5 5-5H7z'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right -7px center; + background-size: 24px; + + .dark & { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%2397a6ba' viewBox='0 0 24 24'%3E%3Cpath d='M7 10l5 5 5-5H7z'/%3E%3C/svg%3E"); + } + } + + &:after { + display: none; + } + } + } + + /* Default style tweaks and enhancements */ + .mat-mdc-text-field-wrapper { + padding: 0; + border-radius: 6px; + border-width: 1px; + border-style: solid; + @apply border-gray-300 bg-white shadow-sm dark:border-gray-500 dark:bg-black dark:bg-opacity-5 #{'!important'}; + + /* Adjust the top spacing and overflow when mat-label present */ + &:not(.mdc-text-field--no-label) { + margin-top: 24px; + overflow: visible; + } + + .mat-mdc-form-field-focus-overlay { + border-radius: 6px; + } + + /* Form field */ + .mat-mdc-form-field-flex { + position: relative; + display: flex; + align-items: stretch; + border-radius: 6px; + padding: 0 16px; + + .mat-mdc-form-field-icon-prefix, + .mat-mdc-form-field-text-prefix { + padding: 0 !important; + + > .mat-icon { + margin-right: 12px; + padding: 0 !important; + } + + > .mat-mdc-icon-button { + margin: 0 4px 0 -10px; + } + + > .mat-mdc-select { + margin-right: 10px; + } + + > .mat-datepicker-toggle { + margin-left: -8px; + } + } + + .mat-mdc-form-field-icon-suffix, + .mat-mdc-form-field-text-suffix { + padding: 0 !important; + + > .mat-icon { + margin-left: 12px; + padding: 0 !important; + } + + > .mat-mdc-icon-button { + margin: 0 -10px 0 4px; + } + + > .mat-mdc-select { + margin-left: 10px; + } + + > .mat-datepicker-toggle { + margin-right: -8px; + } + } + + .mat-mdc-form-field-icon-prefix, + .mat-mdc-form-field-text-prefix, + .mat-mdc-form-field-icon-suffix, + .mat-mdc-form-field-text-suffix { + display: inline-flex; + align-items: center; + justify-content: center; + @apply text-hint #{'!important'}; + + .mat-mdc-icon-button { + width: 40px; + min-width: 40px; + height: 40px; + min-height: 40px; + } + + .mat-icon, + .mat-mdc-icon-button:not([disabled]), + .mat-mdc-select-value { + @apply text-hint; + } + + /* Datepicker default icon size */ + .mat-datepicker-toggle-default-icon { + @apply icon-size-6; + } + + /* Make mat-select usable as prefix and suffix */ + .mat-mdc-select { + display: flex; + align-items: center; + + &:focus { + .mat-mdc-select-trigger { + .mat-mdc-select-value { + @apply text-primary #{'!important'}; + } + + .mat-mdc-select-arrow-wrapper { + .mat-mdc-select-arrow { + border-top-color: var( + --fuse-primary + ) !important; + } + } + } + } + + .mat-mdc-select-trigger { + display: flex; + align-items: center; + + .mat-mdc-select-value { + display: flex; + max-width: none; + + mat-mdc-select-trigger { + .mat-icon { + margin: 0 !important; + } + } + } + + .mat-mdc-select-arrow-wrapper { + display: flex; + align-items: center; + transform: none; + margin-left: 4px; + + .mat-mdc-select-arrow { + min-height: 0; + @apply text-gray-500 dark:text-gray-400 #{'!important'}; + } + } + } + } + } + + /* Infix */ + .mat-mdc-form-field-infix { + position: static; + display: flex; + align-items: center; + width: 88px; + min-height: 48px; + padding: 0; + border: 0; + + /* Floating label - disable floating action */ + .mat-mdc-floating-label { + top: -25px !important; + left: 0 !important; + width: 100% !important; + transform: none !important; + pointer-events: auto; + font-weight: 500; + @apply text-default #{'!important'}; + } + + /* Textarea */ + textarea.mat-mdc-input-element { + margin: 12px 0; + padding: 0 6px 0 0; + } + + /* Chips */ + .mat-mdc-chip-set { + width: 100%; + margin: 0 -8px; + } + } + } + + /* Remove the underline */ + .mdc-line-ripple { + display: none; + } + } + + /* Subscript tweaks */ + .mat-mdc-form-field-subscript-wrapper { + font-size: 12px; + font-weight: 500; + + .mat-mdc-form-field-hint-wrapper, + .mat-mdc-form-field-error-wrapper { + padding: 0; + } + + .mat-mdc-form-field-hint { + @apply text-hint #{'!important'}; + } + } + + /* Adds better alignment for textarea inputs */ + &:has(textarea.mat-mdc-input-element) { + .mat-mdc-text-field-wrapper { + .mat-mdc-form-field-flex { + .mat-mdc-form-field-icon-prefix, + .mat-mdc-form-field-text-prefix, + .mat-mdc-form-field-icon-suffix, + .mat-mdc-form-field-text-suffix { + align-self: flex-start; + padding-top: 14px !important; + } + } + } + } + + /* Rounded */ + &.fuse-mat-rounded { + .mat-mdc-text-field-wrapper { + border-radius: 24px; + } + + /* Emphasized affix */ + &.fuse-mat-emphasized-affix { + .mat-mdc-text-field-wrapper { + .mat-mdc-form-field-flex { + .mat-mdc-form-field-icon-prefix, + .mat-mdc-form-field-text-prefix { + border-radius: 24px 0 0 24px; + + > .mat-icon { + margin-right: 12px; + } + + > .mat-mdc-icon-button { + margin: 0 2px 0 -10px !important; + } + + > .mat-mdc-select { + margin-right: 8px; + } + + > .mat-datepicker-toggle { + margin-right: 4px; + } + + > *:not(.mat-icon):not(.mat-mdc-icon-button):not( + .mat-mdc-select + ):not(.mat-datepicker-toggle) { + margin-right: 12px; + } + } + + .mat-mdc-form-field-icon-suffix, + .mat-mdc-form-field-text-suffix { + border-radius: 0 24px 24px 0; + + > .mat-icon { + margin-left: 12px !important; + } + + > .mat-mdc-icon-button { + margin: 0 -10px 0 2px !important; + } + + > .mat-mdc-select { + margin-left: 12px !important; + } + + > .mat-datepicker-toggle { + margin-left: 4px !important; + } + + > *:not(.mat-icon):not(.mat-mdc-icon-button):not( + .mat-mdc-select + ):not(.mat-datepicker-toggle) { + margin-left: 12px !important; + } + } + } + } + } + } + + /* Dense */ + &.fuse-mat-dense { + .mat-mdc-text-field-wrapper { + .mat-mdc-form-field-flex { + .mat-mdc-form-field-icon-prefix, + .mat-mdc-form-field-text-prefix, + .mat-mdc-form-field-icon-suffix, + .mat-mdc-form-field-text-suffix { + .mat-mdc-icon-button { + width: 32px !important; + min-width: 32px; + height: 32px; + min-height: 32px; + } + } + + .mat-mdc-form-field-icon-prefix, + .mat-mdc-form-field-text-prefix { + > .mat-mdc-icon-button { + margin-left: -6px; + margin-right: 12px; + } + } + + .mat-mdc-form-field-icon-suffix, + .mat-mdc-form-field-text-suffix { + > .mat-mdc-icon-button { + margin-left: 12px; + margin-right: -6px; + } + } + + .mat-mdc-form-field-infix { + min-height: 40px; + + /* Textarea */ + textarea.mat-mdc-input-element { + margin: 8px 0; + } + } + } + } + + /* Adds better alignment for textarea inputs */ + &:has(textarea.mat-mdc-input-element) { + .mat-mdc-text-field-wrapper { + .mat-mdc-form-field-flex { + .mat-mdc-form-field-icon-prefix, + .mat-mdc-form-field-text-prefix, + .mat-mdc-form-field-icon-suffix, + .mat-mdc-form-field-text-suffix { + padding-top: 10px !important; + } + } + } + } + + /* Rounded */ + &.fuse-mat-rounded { + .mat-mdc-text-field-wrapper { + border-radius: 20px; + } + + /* Emphasized affix */ + &.fuse-mat-emphasized-affix { + .mat-mdc-text-field-wrapper { + .mat-mdc-form-field-flex { + .mat-mdc-form-field-icon-prefix, + .mat-mdc-form-field-text-prefix { + border-radius: 20px 0 0 20px !important; + } + + .mat-mdc-form-field-icon-suffix, + .mat-mdc-form-field-text-suffix { + border-radius: 0 20px 20px 0 !important; + } + } + } + } + } + } + + /* Emphasized affix */ + &.fuse-mat-emphasized-affix { + .mat-mdc-text-field-wrapper { + .mat-mdc-form-field-flex { + .mat-mdc-form-field-icon-prefix, + .mat-mdc-form-field-text-prefix { + align-self: stretch !important; + margin: 0 16px 0 -16px !important; + padding-left: 16px !important; + border-radius: 6px 0 0 6px; + border-right-width: 1px; + border-style: solid; + + > .mat-icon { + margin-right: 16px; + } + + > .mat-mdc-icon-button { + margin: 0 6px 0 -10px !important; + } + + > .mat-mdc-select { + margin-right: 12px !important; + } + + > .mat-datepicker-toggle { + margin-right: 8px; + } + + > *:not(.mat-icon):not(.mat-mdc-icon-button):not( + .mat-mdc-select + ):not(.mat-datepicker-toggle) { + margin-right: 16px; + } + } + + .mat-mdc-form-field-icon-suffix, + .mat-mdc-form-field-text-suffix { + align-self: stretch !important; + margin: 0 -16px 0 16px !important; + padding-right: 16px !important; + border-radius: 0 6px 6px 0; + border-left-width: 1px; + border-style: solid; + + > .mat-icon { + margin-left: 16px; + } + + > .mat-mdc-icon-button { + margin: 0 -10px 0 6px !important; + } + + > .mat-mdc-select { + margin: 0 -4px 0 16px !important; + } + + > .mat-datepicker-toggle { + margin-left: 8px; + } + + > *:not(.mat-icon):not(.mat-mdc-icon-button):not( + .mat-mdc-select + ):not(.mat-datepicker-toggle) { + margin-left: 16px; + } + } + + .mat-mdc-form-field-icon-prefix, + .mat-mdc-form-field-text-prefix, + .mat-mdc-form-field-icon-suffix, + .mat-mdc-form-field-text-suffix { + @apply bg-default border-gray-300 dark:border-gray-500 #{'!important'}; + } + } + } + + /* with Textarea */ + &:has(textarea.mat-mdc-input-element) { + .mat-mdc-text-field-wrapper { + .mat-mdc-form-field-flex { + .mat-mdc-form-field-icon-prefix, + .mat-mdc-form-field-text-prefix, + .mat-mdc-form-field-icon-suffix, + .mat-mdc-form-field-text-suffix { + align-items: flex-start; + } + } + } + } + } + + /* Bolder border width */ + &.fuse-mat-bold { + .mat-mdc-text-field-wrapper { + border-width: 2px !important; + } + } +} + +/* "outline" appearance */ +.mat-mdc-form-field.mat-form-field-appearance-outline { + /* Invalid */ + &.mat-form-field-invalid { + .mdc-notched-outline__leading, + .mdc-notched-outline__notch, + .mdc-notched-outline__trailing { + border-color: var(--fuse-warn) !important; + } + } + + /* Focused */ + &.mat-focused:not(.mat-form-field-invalid) { + /* Primary */ + &.mat-primary { + .mdc-notched-outline__leading, + .mdc-notched-outline__notch, + .mdc-notched-outline__trailing { + border-color: var(--fuse-primary) !important; + } + } + + /* Accent */ + &.mat-accent { + .mdc-notched-outline__leading, + .mdc-notched-outline__notch, + .mdc-notched-outline__trailing { + border-color: var(--fuse-accent) !important; + } + } + } + + &:not(.mat-focused):not(.mat-form-field-invalid) { + .mat-mdc-text-field-wrapper { + .mat-mdc-form-field-flex { + .mdc-notched-outline { + .mdc-notched-outline__leading, + .mdc-notched-outline__notch, + .mdc-notched-outline__trailing { + @apply border-slate-300 dark:border-slate-500 #{'!important'}; + } + } + } + } + } + + /* Remove the extra border on the right side of the notch */ + /* Tailwind's global border setter causes this issue */ + .mat-mdc-text-field-wrapper { + .mat-mdc-form-field-flex { + .mdc-notched-outline { + .mdc-notched-outline__notch { + border-right-style: none !important; + } + } + } + } +} + +/* -------------------------------------------------------------------------- */ +/* @ Datepicker +/* -------------------------------------------------------------------------- */ + +/* -------------------------------------------------------------------------- */ +/* @ Icon +/* -------------------------------------------------------------------------- */ +.mat-icon { + display: inline-flex !important; + align-items: center; + justify-content: center; + width: 24px; + min-width: 24px; + height: 24px; + min-height: 24px; + font-size: 24px; + line-height: 24px; + -webkit-appearance: none !important; +} + +/* -------------------------------------------------------------------------- */ +/* @ Inputs +/* -------------------------------------------------------------------------- */ +.mat-mdc-input-element { + &::placeholder { + transition: none !important; + @apply text-hint #{'!important'}; + } + + &::-moz-placeholder { + transition: none !important; + @apply text-hint #{'!important'}; + } + + &::-webkit-input-placeholder { + transition: none !important; + @apply text-hint #{'!important'}; + } + + &:-ms-input-placeholder { + transition: none !important; + @apply text-hint #{'!important'}; + } +} + +/* Invalid */ +.mat-form-field-invalid { + .mat-mdc-input-element { + /* Placeholder color */ + &::placeholder { + @apply text-warn #{'!important'}; + } + + &::-moz-placeholder { + @apply text-warn #{'!important'}; + } + + &::-webkit-input-placeholder { + @apply text-warn #{'!important'}; + } + + &:-ms-input-placeholder { + @apply text-warn #{'!important'}; + } + } +} + +/* -------------------------------------------------------------------------- */ +/* @ Menu +/* -------------------------------------------------------------------------- */ +.mat-mdc-menu-panel { + min-width: 144px !important; + + .mat-mdc-menu-content { + .mat-mdc-menu-item { + .mat-mdc-menu-item-text { + display: flex; + align-items: center; + padding-right: 16px; + } + + .mat-icon-no-color { + --tw-text-opacity: 1; + color: rgba(var(--fuse-mat-icon-rgb), var(--tw-text-opacity)); + } + } + + /* Divider within mat-menu */ + mat-divider { + margin: 8px 0; + } + } +} + +/* -------------------------------------------------------------------------- */ +/* @ Paginator +/* -------------------------------------------------------------------------- */ +.mat-mdc-paginator { + .mat-mdc-paginator-container { + padding: 8px 16px; + justify-content: space-between; + + @screen sm { + justify-content: normal; + } + + /* Page size select */ + .mat-mdc-paginator-page-size { + align-items: center; + min-height: 40px; + margin: 8px; + + .mat-mdc-paginator-page-size-label { + display: none; + margin-right: 12px; + + @screen sm { + display: block; + } + } + + .mat-mdc-paginator-page-size-select { + margin: 0; + + .mat-mdc-text-field-wrapper { + padding: 0 10px; + + .mat-form-field-flex { + min-height: 32px; + } + } + } + } + + /* Range actions */ + .mat-mdc-paginator-range-actions { + margin: 8px 0; + + .mat-mdc-paginator-range-label { + margin-right: 16px; + } + } + } +} + +/* -------------------------------------------------------------------------- */ +/* @ Select +/* -------------------------------------------------------------------------- */ +.mat-mdc-select { + display: inline-flex !important; + + .mat-mdc-select-placeholder { + transition: none !important; + @apply text-hint #{'!important'}; + } + + .mat-mdc-select-trigger { + .mat-mdc-select-value { + position: relative; + display: flex; + max-width: none; + + .mat-mdc-select-value-text { + display: inline-flex; + + > * { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + } + } + } + + .mat-mdc-select-arrow-wrapper { + transform: translateY(0) !important; + + .mat-mdc-select-arrow { + margin: 0 0 0 8px; + @apply text-secondary #{!important}; + } + } +} + +/* -------------------------------------------------------------------------- */ +/* @ Slide Toggle +/* -------------------------------------------------------------------------- */ + +/* -------------------------------------------------------------------------- */ +/* @ Snack bar +/* -------------------------------------------------------------------------- */ +.mat-mdc-snack-bar-container { + .mat-mdc-button.mat-mdc-snack-bar-action:not(:disabled) { + color: #ffffff !important; + + .dark & { + color: #000000 !important; + } + } +} + +/* -------------------------------------------------------------------------- */ +/* @ Stepper +/* -------------------------------------------------------------------------- */ +.mat-step-icon { + /* Do not override the mat-icon color */ + .mat-icon { + color: currentColor !important; + } +} + +.mat-step-label, +.mat-step-label-selected { + font-weight: 500 !important; +} + +/* -------------------------------------------------------------------------- */ +/* @ Table +/* -------------------------------------------------------------------------- */ +.mat-mdc-table { + .mdc-data-table__row:not(.mdc-data-table__row--selected):hover { + background: none !important; + } +} + +/* -------------------------------------------------------------------------- */ +/* @ Tabs +/* -------------------------------------------------------------------------- */ +.mat-mdc-tab-group { + /* No header */ + &.fuse-mat-no-header { + .mat-mdc-tab-header { + height: 0 !important; + max-height: 0 !important; + border: none !important; + visibility: hidden !important; + opacity: 0 !important; + } + } + + &:not(.mat-background-primary):not(.mat-background-accent) { + .mat-mdc-tab-header { + .mat-mdc-tab-label-container { + box-shadow: inset 0 -1px var(--fuse-border); + } + } + } + + .mat-mdc-tab-header { + .mat-mdc-tab-label-container { + margin: 0 24px; + } + } + + .mat-mdc-tab-body-content { + padding: 24px; + } +} + +/* -------------------------------------------------------------------------- */ +/* @ Textarea +/* -------------------------------------------------------------------------- */ +textarea.mat-mdc-input-element { + box-sizing: content-box !important; +} + +/* -------------------------------------------------------------------------- */ +/* @ Toolbar +/* -------------------------------------------------------------------------- */ +.mat-toolbar { + /* Apply primary contrast color */ + &.mat-primary { + .mat-icon { + @apply text-on-primary #{'!important'}; + } + + .text-secondary { + @apply text-on-primary text-opacity-60 #{'!important'}; + } + + .text-hint { + @apply text-on-primary text-opacity-38 #{'!important'}; + } + + .text-disabled { + @apply text-on-primary text-opacity-38 #{'!important'}; + } + + .divider { + @apply text-on-primary text-opacity-12 #{'!important'}; + } + } + + /* Apply accent contrast color */ + &.mat-accent { + .mat-icon { + @apply text-on-accent #{'!important'}; + } + + .text-secondary { + @apply text-on-accent text-opacity-60 #{'!important'}; + } + + .text-hint { + @apply text-on-accent text-opacity-38 #{'!important'}; + } + + .text-disabled { + @apply text-on-accent text-opacity-38 #{'!important'}; + } + + .divider { + @apply text-on-accent text-opacity-12 #{'!important'}; + } + } + + /* Apply warn contrast color */ + &.mat-warn { + .mat-icon { + @apply text-on-warn #{'!important'}; + } + + .text-secondary { + @apply text-on-warn text-opacity-60 #{'!important'}; + } + + .text-hint { + @apply text-on-warn text-opacity-38 #{'!important'}; + } + + .text-disabled { + @apply text-on-warn text-opacity-38 #{'!important'}; + } + + .divider { + @apply text-on-warn text-opacity-12 #{'!important'}; + } + } +} + +/* -------------------------------------------------------------------------- */ +/* @ Tooltip +/* -------------------------------------------------------------------------- */ + +.mat-mdc-tooltip .mdc-tooltip__surface { + background-color: var(--fuse-text-default) !important; + color: white; + + .dark & { + background-color: var(--fuse-text-secondary) !important; + color: var(--fuse-bg-default) !important; + } +} diff --git a/frontend/src/@fuse/styles/overrides/highlightjs.scss b/frontend/src/@fuse/styles/overrides/highlightjs.scss new file mode 100644 index 00000000..bed63676 --- /dev/null +++ b/frontend/src/@fuse/styles/overrides/highlightjs.scss @@ -0,0 +1,81 @@ +/* ----------------------------------------------------------------------------------------------------- */ +/* @ Highlight.js overrides +/* ----------------------------------------------------------------------------------------------------- */ +code[class*='language-'], +pre[class*='language-'] { + .hljs-comment, + .hljs-quote { + color: #8b9fc1; + font-style: italic; + } + + .hljs-doctag, + .hljs-keyword, + .hljs-formula { + color: #22d3ee; + } + + .hljs-name { + color: #e879f9; + } + + .hljs-tag { + color: #bae6fd; + } + + .hljs-section, + .hljs-selector-tag, + .hljs-deletion, + .hljs-subst { + color: #f87f71; + } + + .hljs-literal { + color: #36beff; + } + + .hljs-string, + .hljs-regexp, + .hljs-addition, + .hljs-attribute, + .hljs-meta-string { + color: #bef264; + } + + .hljs-built_in, + .hljs-class .hljs-title { + color: #ffd374; + } + + .hljs-attr, + .hljs-variable, + .hljs-template-variable, + .hljs-type, + .hljs-selector-class, + .hljs-selector-attr, + .hljs-selector-pseudo, + .hljs-number { + color: #22d3ee; + } + + .hljs-symbol, + .hljs-bullet, + .hljs-link, + .hljs-meta, + .hljs-selector-id, + .hljs-title { + color: #e879f9; + } + + .hljs-emphasis { + font-style: italic; + } + + .hljs-strong { + font-weight: 700; + } + + .hljs-link { + text-decoration: underline; + } +} diff --git a/frontend/src/@fuse/styles/overrides/perfect-scrollbar.scss b/frontend/src/@fuse/styles/overrides/perfect-scrollbar.scss new file mode 100644 index 00000000..1ab1b68e --- /dev/null +++ b/frontend/src/@fuse/styles/overrides/perfect-scrollbar.scss @@ -0,0 +1,68 @@ +/* ----------------------------------------------------------------------------------------------------- */ +/* @ Perfect scrollbar overrides +/* ----------------------------------------------------------------------------------------------------- */ +.ps { + position: relative; + + &:hover, + &.ps--focus, + &.ps--scrolling-x, + &.ps--scrolling-y { + > .ps__rail-x, + > .ps__rail-y { + opacity: 1; + } + } + + > .ps__rail-x, + > .ps__rail-y { + z-index: 99999; + } + + > .ps__rail-x { + height: 14px; + background: transparent !important; + transition: none !important; + + &:hover, + &:focus, + &.ps--clicking { + opacity: 1; + + .ps__thumb-x { + height: 10px; + } + } + + .ps__thumb-x { + background: rgba(0, 0, 0, 0.5); + box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.15); + height: 6px; + transition: height 225ms cubic-bezier(0.25, 0.8, 0.25, 1); + } + } + + > .ps__rail-y { + width: 14px; + background: transparent !important; + transition: none !important; + left: auto !important; + + &:hover, + &:focus, + &.ps--clicking { + opacity: 1; + + .ps__thumb-y { + width: 10px; + } + } + + .ps__thumb-y { + background: rgba(0, 0, 0, 0.5); + box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.15); + width: 6px; + transition: width 225ms cubic-bezier(0.25, 0.8, 0.25, 1); + } + } +} diff --git a/frontend/src/@fuse/styles/overrides/quill.scss b/frontend/src/@fuse/styles/overrides/quill.scss new file mode 100644 index 00000000..e16b018f --- /dev/null +++ b/frontend/src/@fuse/styles/overrides/quill.scss @@ -0,0 +1,139 @@ +/* ----------------------------------------------------------------------------------------------------- */ +/* @ Quill editor overrides +/* ----------------------------------------------------------------------------------------------------- */ +.ql-toolbar { + border-radius: 6px 6px 0 0; + padding: 0 !important; + @apply bg-gray-100; + @apply border-gray-300 border-opacity-100 #{'!important'}; + + .dark & { + background-color: rgba(0, 0, 0, 0.05); + @apply border-gray-500 #{'!important'}; + } + + .ql-formats { + margin: 11px 8px !important; + } + + .ql-picker { + &.ql-expanded { + .ql-picker-label { + @apply border-gray-300; + + .dark & { + @apply border-gray-500; + } + } + + .ql-picker-options { + z-index: 10 !important; + @apply bg-card border-gray-300; + + .dark & { + @apply border-gray-500; + } + } + } + + .ql-picker-label { + @apply text-default; + } + + .ql-picker-options { + .ql-picker-item { + @apply text-default; + } + } + } + + .ql-stroke, + .ql-stroke-mitter { + stroke: var(--fuse-icon); + } + + .ql-fill { + fill: var(--fuse-icon); + } + + button:hover, + button:focus, + button.ql-active, + .ql-picker-label:hover, + .ql-picker-label.ql-active, + .ql-picker-item:hover, + .ql-picker-item.ql-selected { + @apply text-primary #{'!important'}; + + .ql-stroke, + .ql-stroke-mitter { + stroke: var(--fuse-primary) !important; + } + + .ql-fill { + fill: var(--fuse-primary) !important; + } + } +} + +.ql-container { + overflow: auto; + min-height: 160px; + max-height: 400px; + border-radius: 0 0 6px 6px; + @apply border-gray-300 border-opacity-100 shadow-sm #{'!important'}; + + .dark & { + @apply border-gray-500 #{'!important'}; + } + + .ql-editor { + @apply bg-card; + + .dark & { + //background-color: rgba(0, 0, 0, 0.05); + } + + &.ql-blank::before { + @apply text-hint; + } + } + + .ql-tooltip { + @apply rounded-md border-gray-300 bg-gray-100 px-3 py-1 shadow-sm; + + .dark & { + @apply border-gray-700 bg-gray-700 shadow-lg #{'!important'}; + } + + // Label + &:before { + @apply text-secondary; + } + + .ql-action, + .ql-remove { + @apply border-gray-300 text-primary; + + .dark & { + @apply border-gray-300 text-primary-400; + } + } + + .ql-action:after { + @apply border-r border-r-gray-300 #{'!important'}; + + .dark & { + @apply border-r-gray-500 #{'!important'}; + } + } + + input { + @apply text-default rounded-sm border-gray-300 bg-white #{'!important'}; + + .dark & { + @apply border-gray-500 bg-gray-700 #{'!important'}; + } + } + } +} diff --git a/frontend/src/@fuse/styles/tailwind.scss b/frontend/src/@fuse/styles/tailwind.scss new file mode 100644 index 00000000..a6d1b6c0 --- /dev/null +++ b/frontend/src/@fuse/styles/tailwind.scss @@ -0,0 +1,143 @@ +/* This injects Tailwind's base styles and any base styles registered by plugins. */ +@tailwind base; + +/* This injects additional styles into Tailwind's base styles layer. */ +@layer base { + * { + /* Text rendering */ + text-rendering: optimizeLegibility; + -o-text-rendering: optimizeLegibility; + -ms-text-rendering: optimizeLegibility; + -moz-text-rendering: optimizeLegibility; + -webkit-text-rendering: optimizeLegibility; + -webkit-tap-highlight-color: transparent; + + /* Remove the focus ring */ + &:focus { + outline: none !important; + } + } + + /* HTML and Body default styles */ + html, + body { + display: flex; + flex-direction: column; + flex: 1 1 auto; + width: 100%; + min-height: 100%; + -webkit-font-smoothing: auto; + -moz-osx-font-smoothing: auto; + } + + /* Font size */ + html { + font-size: 16px; + } + + body { + font-size: 0.875rem; + } + + /* Stylistic alternates for Inter */ + body { + font-feature-settings: 'salt'; + } + + /* Better spacing and border for horizontal rule */ + hr { + margin: 32px 0; + border-bottom-width: 1px; + } + + /* Make images and videos to take up all the available space */ + img { + width: 100%; + vertical-align: top; + } + + /* Fix: Disabled placeholder color is too faded on Safari */ + input[disabled] { + opacity: 1; + -webkit-text-fill-color: currentColor; + } + + /* Set the background and foreground colors */ + body, + .dark, + .light { + @apply text-default bg-default #{'!important'}; + } + + /* Set the border color */ + *, + ::before, + ::after { + --tw-border-opacity: 1 !important; + border-color: rgba(var(--fuse-border-rgb), var(--tw-border-opacity)); + + .dark & { + --tw-border-opacity: 0.12 !important; + } + } + + /* Style scrollbars on platforms other than MacOS and iOS */ + @media only screen and (min-width: 960px) { + body:not(.os-mac) { + ::-webkit-scrollbar { + width: 8px; + height: 8px; + background-color: rgba(0, 0, 0, 0); + } + + ::-webkit-scrollbar:hover { + width: 8px; + height: 8px; + background-color: rgba(0, 0, 0, 0.06); + } + + ::-webkit-scrollbar-thumb { + border: 2px solid transparent; + border-radius: 20px; + box-shadow: inset 0 0 0 20px rgba(0, 0, 0, 0.24); + } + + ::-webkit-scrollbar-thumb:active { + border-radius: 20px; + box-shadow: inset 0 0 0 20px rgba(0, 0, 0, 0.37); + } + + &.dark { + ::-webkit-scrollbar-thumb { + box-shadow: inset 0 0 0 20px rgba(255, 255, 255, 0.24); + } + + ::-webkit-scrollbar-thumb:active { + box-shadow: inset 0 0 0 20px rgba(255, 255, 255, 0.37); + } + } + } + } + + /* Set the foreground color for disabled elements */ + [disabled] { + @apply text-disabled #{'!important'}; + } + + /* Print styles */ + @media print { + /* Make the base font size smaller for print so everything is scaled nicely */ + html { + font-size: 12px !important; + } + + body, + .dark, + .light { + background: none !important; + } + } +} + +/* This injects Tailwind's component classes and any component classes registered by plugins. */ +@tailwind components; diff --git a/frontend/src/@fuse/styles/themes.scss b/frontend/src/@fuse/styles/themes.scss new file mode 100644 index 00000000..b2ca1dc3 --- /dev/null +++ b/frontend/src/@fuse/styles/themes.scss @@ -0,0 +1,257 @@ +@use 'sass:map'; +@use '@angular/material' as mat; +@use 'user-themes' as userThemes; + +/* Set the base colors for light themes */ +$light-base: ( + foreground: ( + base: #000000, + divider: #e2e8f0, + /* slate.200 */ dividers: #e2e8f0, + /* slate.200 */ disabled: #94a3b8, + /* slate.400 */ disabled-button: #94a3b8, + /* slate.400 */ disabled-text: #94a3b8, + /* slate.400 */ elevation: #000000, + hint-text: #94a3b8, + /* slate.400 */ secondary-text: #64748b, + /* slate.500 */ icon: #64748b, + /* slate.500 */ icons: #64748b, + /* slate.500 */ mat-icon: #64748b, + /* slate.500 */ text: #1e293b, + /* slate.800 */ slider-min: #1e293b, + /* slate.800 */ slider-off: #cbd5e1, + /* slate.300 */ slider-off-active: #94a3b8 /* slate.400 */, + ), + background: ( + status-bar: #cbd5e1, + /* slate.300 */ app-bar: #ffffff, + background: #f1f5f9, + /* slate.100 */ hover: rgba(148, 163, 184, 0.12), + /* slate.400 + opacity */ card: #ffffff, + dialog: #ffffff, + disabled-button: rgba(148, 163, 184, 0.38), + /* slate.400 + opacity */ raised-button: #ffffff, + focused-button: #64748b, + /* slate.500 */ selected-button: #e2e8f0, + /* slate.200 */ selected-disabled-button: #e2e8f0, + /* slate.200 */ disabled-button-toggle: #cbd5e1, + /* slate.300 */ unselected-chip: #e2e8f0, + /* slate.200 */ disabled-list-option: #cbd5e1, + /* slate.300 */ tooltip: #1e293b /* slate.800 */, + ), +); + +/* Set the base colors for dark themes */ +$dark-base: ( + foreground: ( + base: #ffffff, + divider: rgba(241, 245, 249, 0.12), + /* slate.100 + opacity */ dividers: rgba(241, 245, 249, 0.12), + /* slate.100 + opacity */ disabled: #475569, + /* slate.600 */ disabled-button: #1e293b, + /* slate.800 */ disabled-text: #475569, + /* slate.600 */ elevation: #000000, + hint-text: #64748b, + /* slate.500 */ secondary-text: #94a3b8, + /* slate.400 */ icon: #f1f5f9, + /* slate.100 */ icons: #f1f5f9, + /* slate.100 */ mat-icon: #94a3b8, + /* slate.400 */ text: #ffffff, + slider-min: #ffffff, + slider-off: #64748b, + /* slate.500 */ slider-off-active: #94a3b8 /* slate.400 */, + ), + background: ( + status-bar: #0f172a, + /* slate.900 */ app-bar: #0f172a, + /* slate.900 */ background: #0f172a, + /* slate.900 */ hover: rgba(255, 255, 255, 0.05), + card: #1e293b, + /* slate.800 */ dialog: #1e293b, + /* slate.800 */ disabled-button: rgba(15, 23, 42, 0.38), + /* slate.900 + opacity */ raised-button: #0f172a, + /* slate.900 */ focused-button: #e2e8f0, + /* slate.200 */ selected-button: rgba(255, 255, 255, 0.05), + selected-disabled-button: #1e293b, + /* slate.800 */ disabled-button-toggle: #0f172a, + /* slate.900 */ unselected-chip: #475569, + /* slate.600 */ disabled-list-option: #e2e8f0, + /* slate.200 */ tooltip: #64748b /* slate.500 */, + ), +); + +/* Include the core Angular Material styles */ +@include mat.core(); + +/* Create a base theme without any color to set the density and typography */ +@include mat.all-component-themes( + ( + color: null, + density: 0, + typography: + mat.m2-define-typography-config( + $font-family: theme('fontFamily.sans'), + $headline-1: + mat.m2-define-typography-level( + 1.875rem, + 2.25rem, + 800, + theme('fontFamily.sans') + ), + $headline-2: + mat.m2-define-typography-level( + 1.25rem, + 1.75rem, + 700, + theme('fontFamily.sans') + ), + $headline-3: + mat.m2-define-typography-level( + 1.125rem, + 1.75rem, + 600, + theme('fontFamily.sans') + ), + $headline-4: + mat.m2-define-typography-level( + 0.875rem, + 1.25rem, + 600, + theme('fontFamily.sans') + ), + $headline-5: + mat.m2-define-typography-level( + 0.875rem, + 1.5rem, + 400, + theme('fontFamily.sans') + ), + $headline-6: + mat.m2-define-typography-level( + 0.875rem, + 1.5rem, + 400, + theme('fontFamily.sans') + ), + $subtitle-1: + mat.m2-define-typography-level( + 1rem, + 1.75rem, + 400, + theme('fontFamily.sans') + ), + $subtitle-2: + mat.m2-define-typography-level( + 0.875rem, + 1.25rem, + 600, + theme('fontFamily.sans') + ), + $body-1: + mat.m2-define-typography-level( + 0.875rem, + 1.5rem, + 400, + theme('fontFamily.sans') + ), + $body-2: + mat.m2-define-typography-level( + 0.875rem, + 1.5rem, + 400, + theme('fontFamily.sans') + ), + $caption: + mat.m2-define-typography-level( + 0.75rem, + 1rem, + 400, + theme('fontFamily.sans') + ), + $button: + mat.m2-define-typography-level( + 0.875rem, + 0.875rem, + 500, + theme('fontFamily.sans') + ), + $overline: + mat.m2-define-typography-level( + 0.75rem, + 2rem, + 500, + theme('fontFamily.sans') + ) + ), + ) +); + +/* Loop through user themes and generate Angular Material themes */ +@each $name, $theme in userThemes.$user-themes { + /* Generate the palettes */ + $palettes: (); + @each $name in (primary, accent, warn) { + /* Define the Angular Material theme */ + $palette: mat.m2-define-palette(map.get($theme, $name)); + + /* Replace the default colors on the defined Material palette */ + $palette: map.merge( + $palette, + ( + default: map.get(map.get($theme, $name), DEFAULT), + lighter: map.get(map.get($theme, $name), 100), + darker: map.get(map.get($theme, $name), 700), + text: map.get(map.get($theme, $name), DEFAULT), + default-contrast: + map.get(map.get(map.get($theme, $name), contrast), DEFAULT), + lighter-contrast: + map.get(map.get(map.get($theme, $name), contrast), 100), + darker-contrast: + map.get(map.get(map.get($theme, $name), contrast), 700), + ) + ); + + $palettes: map.merge($palettes, (#{$name}: $palette)); + } + + /* Define a light & dark Angular Material theme with the generated palettes */ + $light-theme: mat.m2-define-light-theme( + ( + color: $palettes, + ) + ); + + $dark-theme: mat.m2-define-dark-theme( + ( + color: $palettes, + ) + ); + + /* Merge the custom base colors with the generated themes */ + $light-theme-colors: map.merge(map.get($light-theme, color), $light-base); + $light-theme: map.merge( + ( + color: $light-theme-colors, + ), + $light-theme-colors + ); + + $dark-theme-colors: map.merge(map.get($dark-theme, color), $dark-base); + $dark-theme: map.merge( + ( + color: $dark-theme-colors, + ), + $dark-theme-colors + ); + + /* Generate and encapsulate Angular Material themes */ + #{map.get($theme, selector)} .light, + #{map.get($theme, selector)}.light { + @include mat.all-component-colors($light-theme); + } + + #{map.get($theme, selector)} .dark, + #{map.get($theme, selector)}.dark { + @include mat.all-component-colors($dark-theme); + } +} diff --git a/frontend/src/@fuse/styles/user-themes.scss b/frontend/src/@fuse/styles/user-themes.scss new file mode 100644 index 00000000..2735bdac --- /dev/null +++ b/frontend/src/@fuse/styles/user-themes.scss @@ -0,0 +1 @@ +$user-themes: (default: (selector: ".theme-default", primary: (50: #eef2ff, 100: #e0e7ff, 200: #c7d2fe, 300: #a5b4fc, 400: #818cf8, 500: #6366f1, 600: #4f46e5, 700: #4338ca, 800: #3730a3, 900: #312e81, 950: #1e1b4b, DEFAULT: #4f46e5, contrast: (50: #1e1b4b, 100: #1e1b4b, 200: #1e1b4b, 300: #1e1b4b, 400: #1e1b4b, 500: #FFFFFF, 600: #FFFFFF, 700: #FFFFFF, 800: #FFFFFF, 900: #FFFFFF, 950: #FFFFFF, DEFAULT: #FFFFFF)), accent: (50: #f8fafc, 100: #f1f5f9, 200: #e2e8f0, 300: #cbd5e1, 400: #94a3b8, 500: #64748b, 600: #475569, 700: #334155, 800: #1e293b, 900: #0f172a, 950: #020617, DEFAULT: #1e293b, contrast: (50: #020617, 100: #020617, 200: #020617, 300: #020617, 400: #020617, 500: #FFFFFF, 600: #FFFFFF, 700: #FFFFFF, 800: #FFFFFF, 900: #FFFFFF, 950: #FFFFFF, DEFAULT: #FFFFFF)), warn: (50: #fef2f2, 100: #fee2e2, 200: #fecaca, 300: #fca5a5, 400: #f87171, 500: #ef4444, 600: #dc2626, 700: #b91c1c, 800: #991b1b, 900: #7f1d1d, 950: #450a0a, DEFAULT: #dc2626, contrast: (50: #450a0a, 100: #450a0a, 200: #450a0a, 300: #450a0a, 400: #450a0a, 500: #fef2f2, 600: #FFFFFF, 700: #FFFFFF, 800: #FFFFFF, 900: #FFFFFF, 950: #FFFFFF, DEFAULT: #FFFFFF))), brand: (selector: ".theme-brand", primary: (50: #eff5fe, 100: #e2ecfd, 200: #c4dafa, 300: #a1c6f8, 400: #74b0f5, 500: #2196f3, 600: #1e88dc, 700: #1a78c3, 800: #1766a6, 900: #125183, DEFAULT: #2196f3, contrast: (50: #125183, 100: #125183, 200: #125183, 300: #125183, 400: #125183, 500: #FFFFFF, 600: #FFFFFF, 700: #FFFFFF, 800: #FFFFFF, 900: #FFFFFF, DEFAULT: #FFFFFF)), accent: (50: #f8fafc, 100: #f1f5f9, 200: #e2e8f0, 300: #cbd5e1, 400: #94a3b8, 500: #64748b, 600: #475569, 700: #334155, 800: #1e293b, 900: #0f172a, 950: #020617, DEFAULT: #1e293b, contrast: (50: #020617, 100: #020617, 200: #020617, 300: #020617, 400: #020617, 500: #FFFFFF, 600: #FFFFFF, 700: #FFFFFF, 800: #FFFFFF, 900: #FFFFFF, 950: #FFFFFF, DEFAULT: #FFFFFF)), warn: (50: #fef2f2, 100: #fee2e2, 200: #fecaca, 300: #fca5a5, 400: #f87171, 500: #ef4444, 600: #dc2626, 700: #b91c1c, 800: #991b1b, 900: #7f1d1d, 950: #450a0a, DEFAULT: #dc2626, contrast: (50: #450a0a, 100: #450a0a, 200: #450a0a, 300: #450a0a, 400: #450a0a, 500: #fef2f2, 600: #FFFFFF, 700: #FFFFFF, 800: #FFFFFF, 900: #FFFFFF, 950: #FFFFFF, DEFAULT: #FFFFFF))), teal: (selector: ".theme-teal", primary: (50: #f0fdfa, 100: #ccfbf1, 200: #99f6e4, 300: #5eead4, 400: #2dd4bf, 500: #14b8a6, 600: #0d9488, 700: #0f766e, 800: #115e59, 900: #134e4a, 950: #042f2e, DEFAULT: #0d9488, contrast: (50: #042f2e, 100: #042f2e, 200: #042f2e, 300: #042f2e, 400: #042f2e, 500: #042f2e, 600: #042f2e, 700: #FFFFFF, 800: #FFFFFF, 900: #FFFFFF, 950: #FFFFFF, DEFAULT: #042f2e)), accent: (50: #f8fafc, 100: #f1f5f9, 200: #e2e8f0, 300: #cbd5e1, 400: #94a3b8, 500: #64748b, 600: #475569, 700: #334155, 800: #1e293b, 900: #0f172a, 950: #020617, DEFAULT: #1e293b, contrast: (50: #020617, 100: #020617, 200: #020617, 300: #020617, 400: #020617, 500: #FFFFFF, 600: #FFFFFF, 700: #FFFFFF, 800: #FFFFFF, 900: #FFFFFF, 950: #FFFFFF, DEFAULT: #FFFFFF)), warn: (50: #fef2f2, 100: #fee2e2, 200: #fecaca, 300: #fca5a5, 400: #f87171, 500: #ef4444, 600: #dc2626, 700: #b91c1c, 800: #991b1b, 900: #7f1d1d, 950: #450a0a, DEFAULT: #dc2626, contrast: (50: #450a0a, 100: #450a0a, 200: #450a0a, 300: #450a0a, 400: #450a0a, 500: #fef2f2, 600: #FFFFFF, 700: #FFFFFF, 800: #FFFFFF, 900: #FFFFFF, 950: #FFFFFF, DEFAULT: #FFFFFF))), rose: (selector: ".theme-rose", primary: (50: #fff1f2, 100: #ffe4e6, 200: #fecdd3, 300: #fda4af, 400: #fb7185, 500: #f43f5e, 600: #e11d48, 700: #be123c, 800: #9f1239, 900: #881337, 950: #4c0519, DEFAULT: #f43f5e, contrast: (50: #4c0519, 100: #4c0519, 200: #4c0519, 300: #4c0519, 400: #4c0519, 500: #4c0519, 600: #FFFFFF, 700: #FFFFFF, 800: #FFFFFF, 900: #FFFFFF, 950: #FFFFFF, DEFAULT: #4c0519)), accent: (50: #f8fafc, 100: #f1f5f9, 200: #e2e8f0, 300: #cbd5e1, 400: #94a3b8, 500: #64748b, 600: #475569, 700: #334155, 800: #1e293b, 900: #0f172a, 950: #020617, DEFAULT: #1e293b, contrast: (50: #020617, 100: #020617, 200: #020617, 300: #020617, 400: #020617, 500: #FFFFFF, 600: #FFFFFF, 700: #FFFFFF, 800: #FFFFFF, 900: #FFFFFF, 950: #FFFFFF, DEFAULT: #FFFFFF)), warn: (50: #fef2f2, 100: #fee2e2, 200: #fecaca, 300: #fca5a5, 400: #f87171, 500: #ef4444, 600: #dc2626, 700: #b91c1c, 800: #991b1b, 900: #7f1d1d, 950: #450a0a, DEFAULT: #dc2626, contrast: (50: #450a0a, 100: #450a0a, 200: #450a0a, 300: #450a0a, 400: #450a0a, 500: #fef2f2, 600: #FFFFFF, 700: #FFFFFF, 800: #FFFFFF, 900: #FFFFFF, 950: #FFFFFF, DEFAULT: #FFFFFF))), purple: (selector: ".theme-purple", primary: (50: #faf5ff, 100: #f3e8ff, 200: #e9d5ff, 300: #d8b4fe, 400: #c084fc, 500: #a855f7, 600: #9333ea, 700: #7e22ce, 800: #6b21a8, 900: #581c87, 950: #3b0764, DEFAULT: #9333ea, contrast: (50: #3b0764, 100: #3b0764, 200: #3b0764, 300: #3b0764, 400: #3b0764, 500: #FFFFFF, 600: #FFFFFF, 700: #FFFFFF, 800: #FFFFFF, 900: #FFFFFF, 950: #FFFFFF, DEFAULT: #FFFFFF)), accent: (50: #f8fafc, 100: #f1f5f9, 200: #e2e8f0, 300: #cbd5e1, 400: #94a3b8, 500: #64748b, 600: #475569, 700: #334155, 800: #1e293b, 900: #0f172a, 950: #020617, DEFAULT: #1e293b, contrast: (50: #020617, 100: #020617, 200: #020617, 300: #020617, 400: #020617, 500: #FFFFFF, 600: #FFFFFF, 700: #FFFFFF, 800: #FFFFFF, 900: #FFFFFF, 950: #FFFFFF, DEFAULT: #FFFFFF)), warn: (50: #fef2f2, 100: #fee2e2, 200: #fecaca, 300: #fca5a5, 400: #f87171, 500: #ef4444, 600: #dc2626, 700: #b91c1c, 800: #991b1b, 900: #7f1d1d, 950: #450a0a, DEFAULT: #dc2626, contrast: (50: #450a0a, 100: #450a0a, 200: #450a0a, 300: #450a0a, 400: #450a0a, 500: #fef2f2, 600: #FFFFFF, 700: #FFFFFF, 800: #FFFFFF, 900: #FFFFFF, 950: #FFFFFF, DEFAULT: #FFFFFF))), amber: (selector: ".theme-amber", primary: (50: #fffbeb, 100: #fef3c7, 200: #fde68a, 300: #fcd34d, 400: #fbbf24, 500: #f59e0b, 600: #d97706, 700: #b45309, 800: #92400e, 900: #78350f, 950: #451a03, DEFAULT: #f59e0b, contrast: (50: #451a03, 100: #451a03, 200: #451a03, 300: #451a03, 400: #451a03, 500: #451a03, 600: #451a03, 700: #FFFFFF, 800: #FFFFFF, 900: #FFFFFF, 950: #FFFFFF, DEFAULT: #451a03)), accent: (50: #f8fafc, 100: #f1f5f9, 200: #e2e8f0, 300: #cbd5e1, 400: #94a3b8, 500: #64748b, 600: #475569, 700: #334155, 800: #1e293b, 900: #0f172a, 950: #020617, DEFAULT: #1e293b, contrast: (50: #020617, 100: #020617, 200: #020617, 300: #020617, 400: #020617, 500: #FFFFFF, 600: #FFFFFF, 700: #FFFFFF, 800: #FFFFFF, 900: #FFFFFF, 950: #FFFFFF, DEFAULT: #FFFFFF)), warn: (50: #fef2f2, 100: #fee2e2, 200: #fecaca, 300: #fca5a5, 400: #f87171, 500: #ef4444, 600: #dc2626, 700: #b91c1c, 800: #991b1b, 900: #7f1d1d, 950: #450a0a, DEFAULT: #dc2626, contrast: (50: #450a0a, 100: #450a0a, 200: #450a0a, 300: #450a0a, 400: #450a0a, 500: #fef2f2, 600: #FFFFFF, 700: #FFFFFF, 800: #FFFFFF, 900: #FFFFFF, 950: #FFFFFF, DEFAULT: #FFFFFF)))); \ No newline at end of file diff --git a/frontend/src/@fuse/tailwind/plugins/icon-size.js b/frontend/src/@fuse/tailwind/plugins/icon-size.js new file mode 100644 index 00000000..bb9f61bd --- /dev/null +++ b/frontend/src/@fuse/tailwind/plugins/icon-size.js @@ -0,0 +1,47 @@ +const plugin = require('tailwindcss/plugin'); + +module.exports = plugin( + ({ matchUtilities, theme }) => { + matchUtilities( + { + 'icon-size': (value) => ({ + width: value, + height: value, + minWidth: value, + minHeight: value, + fontSize: value, + lineHeight: value, + [`svg`]: { + width: value, + height: value, + }, + }), + }, + { + values: theme('iconSize'), + } + ); + }, + { + theme: { + iconSize: { + 3: '0.75rem', + 3.5: '0.875rem', + 4: '1rem', + 4.5: '1.125rem', + 5: '1.25rem', + 6: '1.5rem', + 7: '1.75rem', + 8: '2rem', + 10: '2.5rem', + 12: '3rem', + 14: '3.5rem', + 16: '4rem', + 18: '4.5rem', + 20: '5rem', + 22: '5.5rem', + 24: '6rem', + }, + }, + } +); diff --git a/frontend/src/@fuse/tailwind/plugins/theming.js b/frontend/src/@fuse/tailwind/plugins/theming.js new file mode 100644 index 00000000..894fdc0a --- /dev/null +++ b/frontend/src/@fuse/tailwind/plugins/theming.js @@ -0,0 +1,383 @@ +const chroma = require('chroma-js'); +const _ = require('lodash'); +const fs = require('fs'); +const path = require('path'); +const colors = require('tailwindcss/colors'); +const plugin = require('tailwindcss/plugin'); +const flattenColorPalette = + require('tailwindcss/lib/util/flattenColorPalette').default; +const generateContrasts = require( + path.resolve(__dirname, '../utils/generate-contrasts') +); +const jsonToSassMap = require( + path.resolve(__dirname, '../utils/json-to-sass-map') +); + +// ----------------------------------------------------------------------------------------------------- +// @ Utilities +// ----------------------------------------------------------------------------------------------------- + +/** + * Normalizes the provided theme by omitting empty values and values that + * start with "on" from each palette. Also sets the correct DEFAULT value + * of each palette. + * + * @param theme + */ +const normalizeTheme = (theme) => { + return _.fromPairs( + _.map( + _.omitBy( + theme, + (palette, paletteName) => + paletteName.startsWith('on') || _.isEmpty(palette) + ), + (palette, paletteName) => [ + paletteName, + { + ...palette, + DEFAULT: palette['DEFAULT'] || palette[500], + }, + ] + ) + ); +}; + +// ----------------------------------------------------------------------------------------------------- +// @ FUSE TailwindCSS Main Plugin +// ----------------------------------------------------------------------------------------------------- +const theming = plugin.withOptions( + (options) => + ({ addComponents, e, theme }) => { + /** + * Create user themes object by going through the provided themes and + * merging them with the provided "default" so, we can have a complete + * set of color palettes for each user theme. + */ + const userThemes = _.fromPairs( + _.map(options.themes, (theme, themeName) => [ + themeName, + _.defaults({}, theme, options.themes['default']), + ]) + ); + + /** + * Normalize the themes and assign it to the themes object. This will + * be the final object that we create a SASS map from + */ + let themes = _.fromPairs( + _.map(userThemes, (theme, themeName) => [ + themeName, + normalizeTheme(theme), + ]) + ); + + /** + * Go through the themes to generate the contrasts and filter the + * palettes to only have "primary", "accent" and "warn" objects. + */ + themes = _.fromPairs( + _.map(themes, (theme, themeName) => [ + themeName, + _.pick( + _.fromPairs( + _.map(theme, (palette, paletteName) => [ + paletteName, + { + ...palette, + contrast: _.fromPairs( + _.map( + generateContrasts(palette), + (color, hue) => [ + hue, + _.get(userThemes[themeName], [ + `on-${paletteName}`, + hue, + ]) || color, + ] + ) + ), + }, + ]) + ), + ['primary', 'accent', 'warn'] + ), + ]) + ); + + /** + * Go through the themes and attach appropriate class selectors so, + * we can use them to encapsulate each theme. + */ + themes = _.fromPairs( + _.map(themes, (theme, themeName) => [ + themeName, + { + selector: `".theme-${themeName}"`, + ...theme, + }, + ]) + ); + + /* Generate the SASS map using the themes object */ + const sassMap = jsonToSassMap( + JSON.stringify({ 'user-themes': themes }) + ); + + /* Get the file path */ + const filename = path.resolve( + __dirname, + '../../styles/user-themes.scss' + ); + + /* Read the file and get its data */ + let data; + try { + data = fs.readFileSync(filename, { encoding: 'utf8' }); + } catch (err) { + console.error(err); + } + + /* Write the file if the map has been changed */ + if (data !== sassMap) { + try { + fs.writeFileSync(filename, sassMap, { encoding: 'utf8' }); + } catch (err) { + console.error(err); + } + } + + /** + * Iterate through the user's themes and build Tailwind components containing + * CSS Custom Properties using the colors from them. This allows switching + * themes by simply replacing a class name as well as nesting them. + */ + addComponents( + _.fromPairs( + _.map(options.themes, (theme, themeName) => [ + themeName === 'default' + ? 'body, .theme-default' + : `.theme-${e(themeName)}`, + _.fromPairs( + _.flatten( + _.map( + flattenColorPalette( + _.fromPairs( + _.flatten( + _.map( + normalizeTheme(theme), + (palette, paletteName) => [ + [ + e(paletteName), + palette, + ], + [ + `on-${e(paletteName)}`, + _.fromPairs( + _.map( + generateContrasts( + palette + ), + ( + color, + hue + ) => [ + hue, + _.get( + theme, + [ + `on-${paletteName}`, + hue, + ] + ) || + color, + ] + ) + ), + ], + ] + ) + ) + ) + ), + (value, key) => [ + [`--fuse-${e(key)}`, value], + [ + `--fuse-${e(key)}-rgb`, + chroma(value).rgb().join(','), + ], + ] + ) + ) + ), + ]) + ) + ); + + /** + * Generate scheme based css custom properties and utility classes + */ + const schemeCustomProps = _.map( + ['light', 'dark'], + (colorScheme) => { + const isDark = colorScheme === 'dark'; + const background = theme( + `fuse.customProps.background.${colorScheme}` + ); + const foreground = theme( + `fuse.customProps.foreground.${colorScheme}` + ); + const lightSchemeSelectors = + 'body.light, .light, .dark .light'; + const darkSchemeSelectors = + 'body.dark, .dark, .light .dark'; + + return { + [isDark ? darkSchemeSelectors : lightSchemeSelectors]: { + /** + * If a custom property is not available, browsers will use + * the fallback value. In this case, we want to use '--is-dark' + * as the indicator of a dark theme so, we can use it like this: + * background-color: var(--is-dark, red); + * + * If we set '--is-dark' as "true" on dark themes, the above rule + * won't work because of the said "fallback value" logic. Therefore, + * we set the '--is-dark' to "false" on light themes and not set it + * at all on dark themes so that the fallback value can be used on + * dark themes. + * + * On light themes, since '--is-dark' exists, the above rule will be + * interpolated as: + * "background-color: false" + * + * On dark themes, since '--is-dark' doesn't exist, the fallback value + * will be used ('red' in this case) and the rule will be interpolated as: + * "background-color: red" + * + * It's easier to understand and remember like this. + */ + ...(!isDark ? { '--is-dark': 'false' } : {}), + + /* Generate custom properties from customProps */ + ..._.fromPairs( + _.flatten( + _.map(background, (value, key) => [ + [`--fuse-${e(key)}`, value], + [ + `--fuse-${e(key)}-rgb`, + chroma(value).rgb().join(','), + ], + ]) + ) + ), + ..._.fromPairs( + _.flatten( + _.map(foreground, (value, key) => [ + [`--fuse-${e(key)}`, value], + [ + `--fuse-${e(key)}-rgb`, + chroma(value).rgb().join(','), + ], + ]) + ) + ), + }, + }; + } + ); + + const schemeUtilities = (() => { + /* Generate general styles & utilities */ + return {}; + })(); + + addComponents(schemeCustomProps); + addComponents(schemeUtilities); + }, + (options) => { + return { + theme: { + extend: { + /** + * Add 'Primary', 'Accent' and 'Warn' palettes as colors so all color utilities + * are generated for them; "bg-primary", "text-on-primary", "bg-accent-600" etc. + * This will also allow using arbitrary values with them such as opacity and such. + */ + colors: _.fromPairs( + _.flatten( + _.map( + _.keys( + flattenColorPalette( + normalizeTheme(options.themes.default) + ) + ), + (name) => [ + [ + name, + `rgba(var(--fuse-${name}-rgb), )`, + ], + [ + `on-${name}`, + `rgba(var(--fuse-on-${name}-rgb), )`, + ], + ] + ) + ) + ), + }, + fuse: { + customProps: { + background: { + light: { + 'bg-app-bar': '#FFFFFF', + 'bg-card': '#FFFFFF', + 'bg-default': colors.slate[100], + 'bg-dialog': '#FFFFFF', + 'bg-hover': chroma(colors.slate[400]) + .alpha(0.12) + .css(), + 'bg-status-bar': colors.slate[300], + }, + dark: { + 'bg-app-bar': colors.slate[900], + 'bg-card': colors.slate[800], + 'bg-default': colors.slate[900], + 'bg-dialog': colors.slate[800], + 'bg-hover': 'rgba(255, 255, 255, 0.05)', + 'bg-status-bar': colors.slate[900], + }, + }, + foreground: { + light: { + 'text-default': colors.slate[800], + 'text-secondary': colors.slate[500], + 'text-hint': colors.slate[400], + 'text-disabled': colors.slate[400], + border: colors.slate[200], + divider: colors.slate[200], + icon: colors.slate[500], + 'mat-icon': colors.slate[500], + }, + dark: { + 'text-default': '#FFFFFF', + 'text-secondary': colors.slate[400], + 'text-hint': colors.slate[500], + 'text-disabled': colors.slate[600], + border: chroma(colors.slate[100]) + .alpha(0.12) + .css(), + divider: chroma(colors.slate[100]) + .alpha(0.12) + .css(), + icon: colors.slate[400], + 'mat-icon': colors.slate[400], + }, + }, + }, + }, + }, + }; + } +); + +module.exports = theming; diff --git a/frontend/src/@fuse/tailwind/plugins/utilities.js b/frontend/src/@fuse/tailwind/plugins/utilities.js new file mode 100644 index 00000000..4045f22f --- /dev/null +++ b/frontend/src/@fuse/tailwind/plugins/utilities.js @@ -0,0 +1,65 @@ +const plugin = require('tailwindcss/plugin'); + +module.exports = plugin(({ addComponents }) => { + /* + * Add base components. These are very important for everything to look + * correct. We are adding these to the 'components' layer because they must + * be defined before pretty much everything else. + */ + addComponents({ + '.mat-icon': { + '--tw-text-opacity': '1', + color: 'rgba(var(--fuse-mat-icon-rgb), var(--tw-text-opacity))', + }, + '.text-default': { + '--tw-text-opacity': '1 !important', + color: 'rgba(var(--fuse-text-default-rgb), var(--tw-text-opacity)) !important', + }, + '.text-secondary': { + '--tw-text-opacity': '1 !important', + color: 'rgba(var(--fuse-text-secondary-rgb), var(--tw-text-opacity)) !important', + }, + '.text-hint': { + '--tw-text-opacity': '1 !important', + color: 'rgba(var(--fuse-text-hint-rgb), var(--tw-text-opacity)) !important', + }, + '.text-disabled': { + '--tw-text-opacity': '1 !important', + color: 'rgba(var(--fuse-text-disabled-rgb), var(--tw-text-opacity)) !important', + }, + '.divider': { + color: 'var(--fuse-divider) !important', + }, + '.bg-card': { + '--tw-bg-opacity': '1 !important', + backgroundColor: + 'rgba(var(--fuse-bg-card-rgb), var(--tw-bg-opacity)) !important', + }, + '.bg-default': { + '--tw-bg-opacity': '1 !important', + backgroundColor: + 'rgba(var(--fuse-bg-default-rgb), var(--tw-bg-opacity)) !important', + }, + '.bg-dialog': { + '--tw-bg-opacity': '1 !important', + backgroundColor: + 'rgba(var(--fuse-bg-dialog-rgb), var(--tw-bg-opacity)) !important', + }, + '.ring-bg-default': { + '--tw-ring-opacity': '1 !important', + '--tw-ring-color': + 'rgba(var(--fuse-bg-default-rgb), var(--tw-ring-opacity)) !important', + }, + '.ring-bg-card': { + '--tw-ring-opacity': '1 !important', + '--tw-ring-color': + 'rgba(var(--fuse-bg-card-rgb), var(--tw-ring-opacity)) !important', + }, + }); + + addComponents({ + '.bg-hover': { + backgroundColor: 'var(--fuse-bg-hover) !important', + }, + }); +}); diff --git a/frontend/src/@fuse/tailwind/utils/generate-contrasts.js b/frontend/src/@fuse/tailwind/utils/generate-contrasts.js new file mode 100644 index 00000000..2a121cc2 --- /dev/null +++ b/frontend/src/@fuse/tailwind/utils/generate-contrasts.js @@ -0,0 +1,37 @@ +const chroma = require('chroma-js'); +const _ = require('lodash'); + +/** + * Generates contrasting counterparts of the given palette. + * The provided palette must be in the same format with + * default Tailwind color palettes. + * + * @param palette + * @private + */ +const generateContrasts = (palette) => { + const lightColor = '#FFFFFF'; + let darkColor = '#FFFFFF'; + + // Iterate through the palette to find the darkest color + _.forEach(palette, (color) => { + darkColor = + chroma.contrast(color, '#FFFFFF') > + chroma.contrast(darkColor, '#FFFFFF') + ? color + : darkColor; + }); + + // Generate the contrasting colors + return _.fromPairs( + _.map(palette, (color, hue) => [ + hue, + chroma.contrast(color, darkColor) > + chroma.contrast(color, lightColor) + ? darkColor + : lightColor, + ]) + ); +}; + +module.exports = generateContrasts; diff --git a/frontend/src/@fuse/tailwind/utils/generate-palette.js b/frontend/src/@fuse/tailwind/utils/generate-palette.js new file mode 100644 index 00000000..0147e448 --- /dev/null +++ b/frontend/src/@fuse/tailwind/utils/generate-palette.js @@ -0,0 +1,100 @@ +const chroma = require('chroma-js'); +const _ = require('lodash'); + +/** + * Generates palettes from the provided configuration. + * Accepts a single color string or a Tailwind-like + * color object. If provided Tailwind-like color object, + * it must have a 500 hue level. + * + * @param config + */ +const generatePalette = (config) => { + // Prepare an empty palette + const palette = { + 50: null, + 100: null, + 200: null, + 300: null, + 400: null, + 500: null, + 600: null, + 700: null, + 800: null, + 900: null, + }; + + // If a single color is provided, + // assign it to the 500 + if (_.isString(config)) { + palette[500] = chroma.valid(config) ? config : null; + } + + // If a partial palette is provided, + // assign the values + if (_.isPlainObject(config)) { + if (!chroma.valid(config[500])) { + throw new Error( + 'You must have a 500 hue in your palette configuration! Make sure the main color of your palette is marked as 500.' + ); + } + + // Remove everything that is not a hue/color entry + config = _.pick(config, Object.keys(palette)); + + // Merge the values + _.mergeWith(palette, config, (objValue, srcValue) => + chroma.valid(srcValue) ? srcValue : null + ); + } + + // Prepare the colors array + const colors = Object.values(palette).filter((color) => color); + + // Generate a very dark and a very light versions of the + // default color to use them as the boundary colors rather + // than using pure white and pure black. This will stop + // in between colors' hue values to slipping into the grays. + colors.unshift( + chroma + .scale(['white', palette[500]]) + .domain([0, 1]) + .mode('lrgb') + .colors(50)[1] + ); + colors.push( + chroma + .scale(['black', palette[500]]) + .domain([0, 1]) + .mode('lrgb') + .colors(10)[1] + ); + + // Prepare the domains array + const domain = [ + 0, + ...Object.entries(palette) + .filter(([key, value]) => value) + .map(([key]) => parseInt(key) / 1000), + 1, + ]; + + // Generate the color scale + const scale = chroma.scale(colors).domain(domain).mode('lrgb'); + + // Build and return the final palette + return { + 50: scale(0.05).hex(), + 100: scale(0.1).hex(), + 200: scale(0.2).hex(), + 300: scale(0.3).hex(), + 400: scale(0.4).hex(), + 500: scale(0.5).hex(), + 600: scale(0.6).hex(), + 700: scale(0.7).hex(), + 800: scale(0.8).hex(), + 900: scale(0.9).hex(), + }; +}; + +module.exports = generatePalette; diff --git a/frontend/src/@fuse/tailwind/utils/json-to-sass-map.js b/frontend/src/@fuse/tailwind/utils/json-to-sass-map.js new file mode 100644 index 00000000..c19736f7 --- /dev/null +++ b/frontend/src/@fuse/tailwind/utils/json-to-sass-map.js @@ -0,0 +1,49 @@ +const _ = require('lodash'); + +module.exports = (data) => { + if (!data) { + return; + } + + data = JSON.parse(data); + + const getSCSS = (chunk) => { + let scss = ''; + + if (typeof chunk === 'object' && !Array.isArray(chunk)) { + _.mapKeys(chunk, (value, key) => { + scss += key + ': '; + + if (typeof value === 'object') { + if (Array.isArray(value)) { + scss += '('; + _.each(value, (val1) => { + if (Array.isArray(val1)) { + _.each(val1, (val2) => { + scss += val2 + ' '; + }); + scss = scss.slice(0, -1) + ', '; + } else { + scss += val1 + ', '; + } + }); + scss = scss.slice(0, -2); + scss += ')'; + } else { + scss += '(' + getSCSS(value) + ')'; + } + } else { + scss += getSCSS(value); + } + scss += ', '; + }); + scss = scss.slice(0, -2); + } else { + scss += chunk; + } + + return scss; + }; + + return '$' + getSCSS(data) + ';'; +}; diff --git a/frontend/src/@fuse/validators/index.ts b/frontend/src/@fuse/validators/index.ts new file mode 100644 index 00000000..5e4748d3 --- /dev/null +++ b/frontend/src/@fuse/validators/index.ts @@ -0,0 +1 @@ +export * from '@fuse/validators/public-api'; diff --git a/frontend/src/@fuse/validators/public-api.ts b/frontend/src/@fuse/validators/public-api.ts new file mode 100644 index 00000000..fc16900a --- /dev/null +++ b/frontend/src/@fuse/validators/public-api.ts @@ -0,0 +1 @@ +export * from '@fuse/validators/validators'; diff --git a/frontend/src/@fuse/validators/validators.ts b/frontend/src/@fuse/validators/validators.ts new file mode 100644 index 00000000..771d12a9 --- /dev/null +++ b/frontend/src/@fuse/validators/validators.ts @@ -0,0 +1,58 @@ +import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms'; + +export class FuseValidators { + /** + * Check for empty (optional fields) values + * + * @param value + */ + static isEmptyInputValue(value: any): boolean { + return value == null || value.length === 0; + } + + /** + * Must match validator + * + * @param controlPath A dot-delimited string values that define the path to the control. + * @param matchingControlPath A dot-delimited string values that define the path to the matching control. + */ + static mustMatch( + controlPath: string, + matchingControlPath: string + ): ValidatorFn { + return (formGroup: AbstractControl): ValidationErrors | null => { + // Get the control and matching control + const control = formGroup.get(controlPath); + const matchingControl = formGroup.get(matchingControlPath); + + // Return if control or matching control doesn't exist + if (!control || !matchingControl) { + return null; + } + + // Delete the mustMatch error to reset the error on the matching control + if (matchingControl.hasError('mustMatch')) { + delete matchingControl.errors.mustMatch; + matchingControl.updateValueAndValidity(); + } + + // Don't validate empty values on the matching control + // Don't validate if values are matching + if ( + this.isEmptyInputValue(matchingControl.value) || + control.value === matchingControl.value + ) { + return null; + } + + // Prepare the validation errors + const errors = { mustMatch: true }; + + // Set the validation error on the matching control + matchingControl.setErrors(errors); + + // Return the errors + return errors; + }; + } +} diff --git a/frontend/src/@fuse/version/fuse-version.ts b/frontend/src/@fuse/version/fuse-version.ts new file mode 100644 index 00000000..c7b7bacc --- /dev/null +++ b/frontend/src/@fuse/version/fuse-version.ts @@ -0,0 +1,3 @@ +import { Version } from '@fuse/version/version'; + +export const FUSE_VERSION = new Version('20.0.0').full; diff --git a/frontend/src/@fuse/version/index.ts b/frontend/src/@fuse/version/index.ts new file mode 100644 index 00000000..aaf27187 --- /dev/null +++ b/frontend/src/@fuse/version/index.ts @@ -0,0 +1 @@ +export * from '@fuse/version/public-api'; diff --git a/frontend/src/@fuse/version/public-api.ts b/frontend/src/@fuse/version/public-api.ts new file mode 100644 index 00000000..8645bbfc --- /dev/null +++ b/frontend/src/@fuse/version/public-api.ts @@ -0,0 +1,2 @@ +export * from '@fuse/version/fuse-version'; +export * from '@fuse/version/version'; diff --git a/frontend/src/@fuse/version/version.ts b/frontend/src/@fuse/version/version.ts new file mode 100644 index 00000000..99a9f935 --- /dev/null +++ b/frontend/src/@fuse/version/version.ts @@ -0,0 +1,19 @@ +/** + * Derived from Angular's version class + */ +export class Version { + public readonly full: string; + public readonly major: string; + public readonly minor: string; + public readonly patch: string; + + /** + * Constructor + */ + constructor(public version: string) { + this.full = version; + this.major = version.split('.')[0]; + this.minor = version.split('.')[1]; + this.patch = version.split('.').slice(2).join('.'); + } +} diff --git a/frontend/src/CONVENTIONS.md b/frontend/src/CONVENTIONS.md deleted file mode 100644 index 21567bd2..00000000 --- a/frontend/src/CONVENTIONS.md +++ /dev/null @@ -1 +0,0 @@ -The angular unit tests should use the Page Object Model/Pattern approach. Each component should have a corresponding component.po.ts file which accesses the component through the DOM to avoid coupling to implementation details. diff --git a/frontend/src/_redirects b/frontend/src/_redirects new file mode 100644 index 00000000..bbb3e7a1 --- /dev/null +++ b/frontend/src/_redirects @@ -0,0 +1 @@ +/* /index.html 200 diff --git a/frontend/src/app/@shared/http/api-prefix.interceptor.spec.ts b/frontend/src/app/@shared/http/api-prefix.interceptor.spec.ts deleted file mode 100644 index 0c5b2ca1..00000000 --- a/frontend/src/app/@shared/http/api-prefix.interceptor.spec.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { Type } from '@angular/core'; -import { TestBed } from '@angular/core/testing'; -import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; -import { HTTP_INTERCEPTORS, HttpClient } from '@angular/common/http'; - -import { environment } from '@env/environment'; -import { ApiPrefixInterceptor } from './api-prefix.interceptor'; - -describe('ApiPrefixInterceptor', () => { - let http: HttpClient; - let httpMock: HttpTestingController; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [ - { - provide: HTTP_INTERCEPTORS, - useClass: ApiPrefixInterceptor, - multi: true, - }, - ], - }); - - http = TestBed.inject(HttpClient); - httpMock = TestBed.inject(HttpTestingController as Type); - }); - - afterEach(() => { - httpMock.verify(); - }); - - it('should prepend environment.serverUrl to the request url', () => { - // Act - http.get('/toto').subscribe(); - - // Assert - httpMock.expectOne({ url: environment.serverUrl + '/toto' }); - }); - - it('should not prepend environment.serverUrl to request url', () => { - // Act - http.get('hTtPs://domain.com/toto').subscribe(); - - // Assert - httpMock.expectOne({ url: 'hTtPs://domain.com/toto' }); - }); -}); diff --git a/frontend/src/app/@shared/http/api-prefix.interceptor.ts b/frontend/src/app/@shared/http/api-prefix.interceptor.ts deleted file mode 100644 index 9b288073..00000000 --- a/frontend/src/app/@shared/http/api-prefix.interceptor.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http'; -import { Observable } from 'rxjs'; - -import { environment } from '@env/environment'; - -/** - * Prefixes all requests not starting with `http[s]` with `environment.serverUrl`. - */ -@Injectable({ - providedIn: 'root', -}) -export class ApiPrefixInterceptor implements HttpInterceptor { - intercept(request: HttpRequest, next: HttpHandler): Observable> { - if (!/^(http|https):/i.test(request.url)) { - request = request.clone({ url: environment.serverUrl + request.url }); - } - return next.handle(request); - } -} diff --git a/frontend/src/app/@shared/http/error-handler.interceptor.spec.ts b/frontend/src/app/@shared/http/error-handler.interceptor.spec.ts deleted file mode 100644 index c3854555..00000000 --- a/frontend/src/app/@shared/http/error-handler.interceptor.spec.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Type } from '@angular/core'; -import { TestBed } from '@angular/core/testing'; -import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; -import { HTTP_INTERCEPTORS, HttpClient } from '@angular/common/http'; - -import { ErrorHandlerInterceptor } from './error-handler.interceptor'; - -describe('ErrorHandlerInterceptor', () => { - let errorHandlerInterceptor: ErrorHandlerInterceptor; - let http: HttpClient; - let httpMock: HttpTestingController; - - function createInterceptor() { - errorHandlerInterceptor = new ErrorHandlerInterceptor(); - return errorHandlerInterceptor; - } - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [ - { - provide: HTTP_INTERCEPTORS, - useFactory: createInterceptor, - multi: true, - }, - ], - }); - - http = TestBed.inject(HttpClient); - httpMock = TestBed.inject(HttpTestingController as Type); - }); - - afterEach(() => { - httpMock.verify(); - }); - - it('should catch error and call error handler', () => { - // Arrange - // Note: here we spy on private method since target is customization here, - // but you should replace it by actual behavior in your app - jest.spyOn(ErrorHandlerInterceptor.prototype as any, 'errorHandler'); - - // Act - http.get('/toto').subscribe( - () => fail('should error'), - () => { - // Assert - expect((ErrorHandlerInterceptor.prototype as any).errorHandler).toHaveBeenCalled(); - } - ); - - httpMock.expectOne({}).flush(null, { - status: 404, - statusText: 'error', - }); - }); -}); diff --git a/frontend/src/app/@shared/http/error-handler.interceptor.ts b/frontend/src/app/@shared/http/error-handler.interceptor.ts deleted file mode 100644 index 7597daa4..00000000 --- a/frontend/src/app/@shared/http/error-handler.interceptor.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { catchError } from 'rxjs/operators'; - -import { environment } from '@env/environment'; -import { Logger } from '../logger.service'; - -const log = new Logger('ErrorHandlerInterceptor'); - -/** - * Adds a default error handler to all requests. - */ -@Injectable({ - providedIn: 'root', -}) -export class ErrorHandlerInterceptor implements HttpInterceptor { - intercept(request: HttpRequest, next: HttpHandler): Observable> { - return next.handle(request).pipe(catchError((error) => this.errorHandler(error))); - } - - // Customize the default error handler here if needed - private errorHandler(response: HttpEvent): Observable> { - if (!environment.production) { - // Do something with the error - log.error('Request error', response); - } - throw response; - } -} diff --git a/frontend/src/app/@shared/index.ts b/frontend/src/app/@shared/index.ts deleted file mode 100644 index dcbf8000..00000000 --- a/frontend/src/app/@shared/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -export * from './shared.module'; -export * from './http/api-prefix.interceptor'; -export * from './http/error-handler.interceptor'; -export * from './loader/loader.component'; -export * from './route-reusable-strategy'; -export * from './logger.service'; -export * from '@ngneat/until-destroy'; - -export type Data = { - data: T; -}; - -export type AgentType = 'xml' | 'codegen'; diff --git a/frontend/src/app/@shared/loader/loader.component.html b/frontend/src/app/@shared/loader/loader.component.html deleted file mode 100644 index ea85ef37..00000000 --- a/frontend/src/app/@shared/loader/loader.component.html +++ /dev/null @@ -1,4 +0,0 @@ -
- - {{ message }} -
diff --git a/frontend/src/app/@shared/loader/loader.component.scss b/frontend/src/app/@shared/loader/loader.component.scss deleted file mode 100644 index 7c4ccc72..00000000 --- a/frontend/src/app/@shared/loader/loader.component.scss +++ /dev/null @@ -1,8 +0,0 @@ -.mat-progress-spinner { - display: inline-block; - vertical-align: middle; -} - -.message { - margin-left: 0.5em; -} diff --git a/frontend/src/app/@shared/loader/loader.component.spec.ts b/frontend/src/app/@shared/loader/loader.component.spec.ts deleted file mode 100644 index c796e2c9..00000000 --- a/frontend/src/app/@shared/loader/loader.component.spec.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { FlexLayoutModule } from '@angular/flex-layout'; - -import { MaterialModule } from '@app/material.module'; -import { LoaderComponent } from './loader.component'; - -describe('LoaderComponent', () => { - let component: LoaderComponent; - let fixture: ComponentFixture; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [BrowserAnimationsModule, FlexLayoutModule, MaterialModule], - declarations: [LoaderComponent], - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(LoaderComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should not be visible by default', () => { - // Arrange - const element = fixture.nativeElement; - const div = element.querySelectorAll('div')[0]; - - // Assert - expect(div.getAttribute('hidden')).not.toBeNull(); - }); - - it('should be visible when app is loading', () => { - // Arrange - const element = fixture.nativeElement; - const div = element.querySelectorAll('div')[0]; - - // Act - fixture.componentInstance.isLoading = true; - fixture.detectChanges(); - - // Assert - expect(div.getAttribute('hidden')).toBeNull(); - }); - - it('should not display a message by default', () => { - // Arrange - const element = fixture.nativeElement; - const span = element.querySelectorAll('span')[0]; - - // Assert - expect(span.textContent).toBe(''); - }); - - it('should display specified message', () => { - // Arrange - const element = fixture.nativeElement; - const span = element.querySelectorAll('span')[0]; - - // Act - fixture.componentInstance.message = 'testing'; - fixture.detectChanges(); - - // Assert - expect(span.textContent).toBe('testing'); - }); -}); diff --git a/frontend/src/app/@shared/loader/loader.component.ts b/frontend/src/app/@shared/loader/loader.component.ts deleted file mode 100644 index 3355bcdc..00000000 --- a/frontend/src/app/@shared/loader/loader.component.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Component, OnInit, Input } from '@angular/core'; - -@Component({ - selector: 'app-loader', - templateUrl: './loader.component.html', - styleUrls: ['./loader.component.scss'], -}) -export class LoaderComponent implements OnInit { - @Input() isLoading = false; - @Input() size = 1; - @Input() message: string | undefined; - - constructor() {} - - ngOnInit() {} -} diff --git a/frontend/src/app/@shared/logger.service.spec.ts b/frontend/src/app/@shared/logger.service.spec.ts deleted file mode 100644 index bf0ea5be..00000000 --- a/frontend/src/app/@shared/logger.service.spec.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { Logger, LogLevel, LogOutput } from './logger.service'; - -const logMethods = ['log', 'info', 'warn', 'error']; - -describe('Logger', () => { - let savedConsole: any[]; - let savedLevel: LogLevel; - let savedOutputs: LogOutput[]; - - beforeAll(() => { - savedConsole = []; - logMethods.forEach((m) => { - savedConsole[m] = console[m]; - console[m] = () => {}; - }); - savedLevel = Logger.level; - savedOutputs = Logger.outputs; - }); - - beforeEach(() => { - Logger.level = LogLevel.Debug; - }); - - afterAll(() => { - logMethods.forEach((m) => { - console[m] = savedConsole[m]; - }); - Logger.level = savedLevel; - Logger.outputs = savedOutputs; - }); - - it('should create an instance', () => { - expect(new Logger()).toBeTruthy(); - }); - - it('should add a new LogOutput and receives log entries', () => { - // Arrange - const outputSpy = jest.fn(); - const log = new Logger('test'); - - // Act - Logger.outputs.push(outputSpy); - - log.debug('d'); - log.info('i'); - log.warn('w'); - log.error('e', { error: true }); - - // Assert - expect(outputSpy).toHaveBeenCalled(); - expect(outputSpy.mock.calls.length).toBe(4); - expect(outputSpy).toHaveBeenCalledWith('test', LogLevel.Debug, 'd'); - expect(outputSpy).toHaveBeenCalledWith('test', LogLevel.Info, 'i'); - expect(outputSpy).toHaveBeenCalledWith('test', LogLevel.Warning, 'w'); - expect(outputSpy).toHaveBeenCalledWith('test', LogLevel.Error, 'e', { error: true }); - }); - - it('should add a new LogOutput and receives only production log entries', () => { - // Arrange - const outputSpy = jest.fn(); - const log = new Logger('test'); - - // Act - Logger.outputs.push(outputSpy); - Logger.enableProductionMode(); - - log.debug('d'); - log.info('i'); - log.warn('w'); - log.error('e', { error: true }); - - // Assert - expect(outputSpy).toHaveBeenCalled(); - expect(outputSpy.mock.calls.length).toBe(2); - expect(outputSpy).toHaveBeenCalledWith('test', LogLevel.Warning, 'w'); - expect(outputSpy).toHaveBeenCalledWith('test', LogLevel.Error, 'e', { error: true }); - }); -}); diff --git a/frontend/src/app/@shared/logger.service.ts b/frontend/src/app/@shared/logger.service.ts deleted file mode 100644 index 60e16aec..00000000 --- a/frontend/src/app/@shared/logger.service.ts +++ /dev/null @@ -1,111 +0,0 @@ -/** - * Simple logger system with the possibility of registering custom outputs. - * - * 4 different log levels are provided, with corresponding methods: - * - debug : for debug information - * - info : for informative status of the application (success, ...) - * - warning : for non-critical errors that do not prevent normal application behavior - * - error : for critical errors that prevent normal application behavior - * - * Example usage: - * ``` - * import { Logger } from 'app/core/logger.service'; - * - * const log = new Logger('myFile'); - * ... - * log.debug('something happened'); - * ``` - * - * To disable debug and info logs in production, add this snippet to your root component: - * ``` - * export class AppComponent implements OnInit { - * ngOnInit() { - * if (environment.production) { - * Logger.enableProductionMode(); - * } - * ... - * } - * } - * - * If you want to process logs through other outputs than console, you can add LogOutput functions to Logger.outputs. - */ - -/** - * The possible log levels. - * LogLevel.Off is never emitted and only used with Logger.level property to disable logs. - */ -export enum LogLevel { - Off = 0, - Error, - Warning, - Info, - Debug, -} - -/** - * Log output handler function. - */ -export type LogOutput = (source: string | undefined, level: LogLevel, ...objects: any[]) => void; - -export class Logger { - /** - * Current logging level. - * Set it to LogLevel.Off to disable logs completely. - */ - static level = LogLevel.Debug; - - /** - * Additional log outputs. - */ - static outputs: LogOutput[] = []; - - /** - * Enables production mode. - * Sets logging level to LogLevel.Warning. - */ - static enableProductionMode() { - Logger.level = LogLevel.Warning; - } - - constructor(private source?: string) {} - - /** - * Logs messages or objects with the debug level. - * Works the same as console.log(). - */ - debug(...objects: any[]) { - this.log(console.log, LogLevel.Debug, objects); - } - - /** - * Logs messages or objects with the info level. - * Works the same as console.log(). - */ - info(...objects: any[]) { - this.log(console.info, LogLevel.Info, objects); - } - - /** - * Logs messages or objects with the warning level. - * Works the same as console.log(). - */ - warn(...objects: any[]) { - this.log(console.warn, LogLevel.Warning, objects); - } - - /** - * Logs messages or objects with the error level. - * Works the same as console.log(). - */ - error(...objects: any[]) { - this.log(console.error, LogLevel.Error, objects); - } - - private log(func: (...args: any[]) => void, level: LogLevel, objects: any[]) { - if (level <= Logger.level) { - const log = this.source ? ['[' + this.source + ']'].concat(objects) : objects; - func.apply(console, log); - Logger.outputs.forEach((output) => output.apply(output, [this.source, level, ...objects])); - } - } -} diff --git a/frontend/src/app/@shared/route-reusable-strategy.ts b/frontend/src/app/@shared/route-reusable-strategy.ts deleted file mode 100644 index d33896f6..00000000 --- a/frontend/src/app/@shared/route-reusable-strategy.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy } from '@angular/router'; -import { Injectable } from '@angular/core'; - -/** - * A route strategy allowing for explicit route reuse. - * Used as a workaround for https://github.com/angular/angular/issues/18374 - * To reuse a given route, add `data: { reuse: true }` to the route definition. - */ -@Injectable() -export class RouteReusableStrategy extends RouteReuseStrategy { - public shouldDetach(route: ActivatedRouteSnapshot): boolean { - return false; - } - - public store(route: ActivatedRouteSnapshot, detachedTree: DetachedRouteHandle | null): void {} - - public shouldAttach(route: ActivatedRouteSnapshot): boolean { - return false; - } - - public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null { - return null; - } - - public shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean { - // Reuse the route if the RouteConfig is the same, or if both routes use the - // same component, because the latter can have different RouteConfigs. - return ( - future.routeConfig === curr.routeConfig || - Boolean(future.routeConfig?.component && future.routeConfig?.component === curr.routeConfig?.component) - ); - } -} diff --git a/frontend/src/app/@shared/services/llm.service.ts b/frontend/src/app/@shared/services/llm.service.ts deleted file mode 100644 index 2a0c9eb8..00000000 --- a/frontend/src/app/@shared/services/llm.service.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { environment } from '@env/environment'; - -export interface LLM { - id: string; - name: string; - isConfigured: boolean; -} - -@Injectable({ - providedIn: 'root', -}) -export class LlmService { - private apiUrl = `${environment.serverUrl}/api/llms`; - - constructor(private http: HttpClient) {} - - getLlms(): Observable { - return this.http.get(`${this.apiUrl}/list`); - } -} diff --git a/frontend/src/app/@shared/shared.module.ts b/frontend/src/app/@shared/shared.module.ts deleted file mode 100644 index cb54d4c4..00000000 --- a/frontend/src/app/@shared/shared.module.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { TranslateModule } from '@ngx-translate/core'; -import { FlexLayoutModule } from '@angular/flex-layout'; -import { ReactiveFormsModule, FormsModule } from '@angular/forms'; - -import { MaterialModule } from '@app/material.module'; -import { LoaderComponent } from './loader/loader.component'; -import { LlmService } from '@app/shared/services/llm.service'; - -@NgModule({ - imports: [FlexLayoutModule, MaterialModule, TranslateModule, CommonModule, ReactiveFormsModule, FormsModule], - declarations: [LoaderComponent], - exports: [LoaderComponent, ReactiveFormsModule, FormsModule], - providers: [LlmService], -}) -export class SharedModule {} diff --git a/frontend/src/app/about/about-routing.module.ts b/frontend/src/app/about/about-routing.module.ts deleted file mode 100644 index 861039d3..00000000 --- a/frontend/src/app/about/about-routing.module.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { NgModule } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; -import { marker } from '@biesbjerg/ngx-translate-extract-marker'; - -import { AboutComponent } from './about.component'; - -const routes: Routes = [ - // Module is lazy loaded, see app-routing.module.ts - { path: '', component: AboutComponent, data: { title: marker('About') } }, -]; - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule], - providers: [], -}) -export class AboutRoutingModule {} diff --git a/frontend/src/app/about/about.component.html b/frontend/src/app/about/about.component.html deleted file mode 100644 index 55ede8f4..00000000 --- a/frontend/src/app/about/about.component.html +++ /dev/null @@ -1,11 +0,0 @@ -
- -

- APP_NAME -

- - code - Version {{ version }} - -
-
diff --git a/frontend/src/app/about/about.component.scss b/frontend/src/app/about/about.component.scss deleted file mode 100644 index 531efd72..00000000 --- a/frontend/src/app/about/about.component.scss +++ /dev/null @@ -1,8 +0,0 @@ -.container { - text-align: center; - padding: 1rem; -} - -.mat-icon { - vertical-align: middle; -} diff --git a/frontend/src/app/about/about.component.spec.ts b/frontend/src/app/about/about.component.spec.ts deleted file mode 100644 index 3161c917..00000000 --- a/frontend/src/app/about/about.component.spec.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { FlexLayoutModule } from '@angular/flex-layout'; - -import { MaterialModule } from '@app/material.module'; -import { AboutComponent } from './about.component'; - -describe('AboutComponent', () => { - let component: AboutComponent; - let fixture: ComponentFixture; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [BrowserAnimationsModule, FlexLayoutModule, MaterialModule], - declarations: [AboutComponent], - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(AboutComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/frontend/src/app/about/about.component.ts b/frontend/src/app/about/about.component.ts deleted file mode 100644 index def78df0..00000000 --- a/frontend/src/app/about/about.component.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Component, OnInit } from '@angular/core'; - -import { environment } from '@env/environment'; - -@Component({ - selector: 'app-about', - templateUrl: './about.component.html', - styleUrls: ['./about.component.scss'], -}) -export class AboutComponent implements OnInit { - version: string | null = environment.version; - - constructor() {} - - ngOnInit() {} -} diff --git a/frontend/src/app/about/about.module.ts b/frontend/src/app/about/about.module.ts deleted file mode 100644 index c9554610..00000000 --- a/frontend/src/app/about/about.module.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { TranslateModule } from '@ngx-translate/core'; -import { FlexLayoutModule } from '@angular/flex-layout'; - -import { MaterialModule } from '@app/material.module'; -import { AboutRoutingModule } from './about-routing.module'; -import { AboutComponent } from './about.component'; - -@NgModule({ - imports: [CommonModule, TranslateModule, FlexLayoutModule, MaterialModule, AboutRoutingModule], - declarations: [AboutComponent], -}) -export class AboutModule {} diff --git a/frontend/src/app/agent-event.service.ts b/frontend/src/app/agent-event.service.ts deleted file mode 100644 index a7972e49..00000000 --- a/frontend/src/app/agent-event.service.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Injectable, EventEmitter } from '@angular/core'; -import { environment } from '@env/environment'; - -@Injectable({ - providedIn: 'root', -}) -export class AgentEventService { - private eventSource: EventSource | null = null; - public messageEvent: EventEmitter = new EventEmitter(); - - constructor() {} - - connect(agentId: string) { - this.eventSource = new EventSource(`${environment.serverUrl}/api/agent/v1/listen/${agentId}`); - - this.eventSource.onmessage = (event) => { - const data = JSON.parse(event.data); - this.messageEvent.emit(data); - }; - - this.eventSource.onerror = (error) => { - console.error('SSE error', error); - this.eventSource?.close(); - }; - } - - disconnect() { - if (this.eventSource) { - this.eventSource.close(); - } - } -} diff --git a/frontend/src/app/agent/agent-routing.module.ts b/frontend/src/app/agent/agent-routing.module.ts deleted file mode 100644 index 10c0c895..00000000 --- a/frontend/src/app/agent/agent-routing.module.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { NgModule } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; -import { marker } from '@biesbjerg/ngx-translate-extract-marker'; - -import { AgentComponent } from './agent.component'; - -const routes: Routes = [ - // Module is lazy loaded, see app-routing.module.ts - { path: ':agentId', component: AgentComponent, data: { title: marker('Agent') } }, -]; - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule], - providers: [], -}) -export class AgentRoutingModule {} diff --git a/frontend/src/app/agent/agent.component.html b/frontend/src/app/agent/agent.component.html deleted file mode 100644 index 75e964df..00000000 --- a/frontend/src/app/agent/agent.component.html +++ /dev/null @@ -1,421 +0,0 @@ - - - -
- Feedback Requested - - - - - Question: - - {{ - agentDetails.functionCallHistory[agentDetails.functionCallHistory.length - 1].parameters[ - 'request' - ].trim() | slice : 0 : 140 - }}... - - - -
{{ agentDetails.functionCallHistory[agentDetails.functionCallHistory.length - 1].parameters['request'].trim() }}
-
- - - -
- - - - -
-
- - -
- Agent Error - - - - - Error: - {{ agentDetails.error | slice : 0 : 150 }}... - - - -
{{ agentDetails.error }}
-
- - - -
- - - - -
-
- - -
- Human In Loop check - - - - - - - - - -
-
- - - - -
-
- - Name - {{ agentDetails.name }} - -
-
- refresh - - storage - -
-
- Type - {{ agentDetails.type }} - Parent Agent ID - {{ agentDetails.parentAgentId }} - User ID - {{ agentDetails.userId }} - - State - {{ displayState(agentDetails.state) }} - Resume agent - - - - - - User Prompt - {{ - agentDetails.userPrompt | slice : 0 : 150 - }} - - - -
{{ agentDetails.userPrompt }}
-
- - - - - Output - {{ - output | slice : 0 : 150 - }} - - - -
{{ output }}
-
- - - - Planning Response: - {{ agentDetails.planningResponse }} - - - - Functions -
- {{ agentDetails.functions.sort().join(', ') }} - -
-
- - - LLMS -
-
- Easy: - {{ getLlmName(agentDetails.llms.easy) }} -
-
- Med: - {{ getLlmName(agentDetails.llms.medium) }} -
-
- Hard: - {{ getLlmName(agentDetails.llms.hard) }} -
-
-
- - Cost ${{ - agentDetails.cost | number : '1.2-2' - }} - - - Working Directory - {{ agentDetails.fileSystem.workingDirectory }} - -
-
-
- - -
- - {{ entry.key }} - - -
{{ entry.value }}
-
-
-
-
- - - - {{ invoked.function_name }} - -
-

- {{ param.key }} {{ param.value }} -

-
- - - - Output: - {{ - invoked.stdoutSummary ?? invoked.stdout | slice : 0 : 150 - }} - - -
-
- - - - Errors: - {{ - invoked.stderrSummary ?? invoked.stderr | slice : 0 : 150 - }} - - -
-
-
-
-
-

No function calls found for this agent.

-
-
- - - - {{ call.callStack }} {{ call.description }} - storage - -

- LLM: {{ call.llmId }}    Request Time: - {{ call.requestTime | date : 'medium' }}.    Total Time: - {{ ((call.totalTime ?? 0) / 1000).toFixed(1) }}s   Tokens in/out: - {{ call.inputTokens }}/{{ call.outputTokens }}   Cost: ${{ - call.cost?.toFixed(4) - }} -

- - - - - System Prompt: - {{ call.systemPrompt | slice : 0 : 50 }} ... - - - - -
{{ call.systemPrompt }}
-
- - - - - Function Call History: - - {{ extractFunctionCallHistory(call.userPrompt) | slice : 0 : 150 }} ... - - - - -
{{ extractFunctionCallHistory(call.userPrompt) }}
-
- - - - - Memory Contents: - - {{ extractMemoryContent(call.userPrompt) | slice : 0 : 150 }} - - - - -
{{ extractMemoryContent(call.userPrompt) }}
-
- - - - - User Prompt: - - {{ removeFunctionCallHistory(removeMemoryContent(call.userPrompt)) | slice : 0 : 150 }} ... - - - - -
{{ removeFunctionCallHistory(removeMemoryContent(call.userPrompt)).trim() }}
-
- - - - - Response Text: - - {{ call.responseText | slice : 0 : 150 }} ... - - - - -
{{ call.responseText }}
-
- - -
-
-
-

No LLM calls found for this agent.

-
-
-
diff --git a/frontend/src/app/agent/agent.component.spec.ts b/frontend/src/app/agent/agent.component.spec.ts deleted file mode 100644 index f3568bd6..00000000 --- a/frontend/src/app/agent/agent.component.spec.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { AgentComponent } from './agent.component'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { RouterTestingModule } from '@angular/router/testing'; -import { ReactiveFormsModule } from '@angular/forms'; -import { MaterialModule } from '@app/material.module'; -import { of, throwError } from 'rxjs'; -import { MatSnackBarModule } from '@angular/material/snack-bar'; - -describe('AgentComponent', () => { - let component: AgentComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [AgentComponent], - imports: [HttpClientTestingModule, RouterTestingModule, ReactiveFormsModule, MaterialModule, MatSnackBarModule], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(AgentComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - // it('should save functions and update UI', () => { - // const httpClientSpy = jasmine.createSpyObj('HttpClient', ['post']); - // httpClientSpy.post.and.returnValue(of({})); - // component.http = httpClientSpy as any; - // component.agentDetails = { functions: ['func1', 'func2', 'func3'] }; - // component.agentId = 'test-agent-id'; - // component.functionSelections = [true, false, true]; - // component.editMode = true; - // - // component.saveFunctions(); - // - // expect(httpClientSpy.post).toHaveBeenCalledWith(`${environment.serverUrl}/agent/v1/update-functions`, { - // agentId: 'test-agent-id', - // functions: ['func1', 'func3'], - // }); - // expect(component.editMode).toBeFalse(); - // expect(component.isSavingFunctions).toBeFalse(); - // }); - // - // it('should handle errors when saving functions', () => { - // const httpClientSpy = jasmine.createSpyObj('HttpClient', ['post']); - // httpClientSpy.post.and.returnValue(throwError(() => new Error('Test error'))); - // component.http = httpClientSpy as any; - // component.agentDetails = { functions: ['func1', 'func2'] }; - // component.agentId = 'test-agent-id'; - // component.functionSelections = [true, true]; - // component.editMode = true; - // - // component.saveFunctions(); - // - // expect(httpClientSpy.post).toHaveBeenCalled(); - // expect(component.isSavingFunctions).toBeFalse(); - // expect(component.editMode).toBeTrue(); - // }); - // - // it('should set isSavingFunctions to true when saving functions', () => { - // const httpClientSpy = jasmine.createSpyObj('HttpClient', ['post']); - // httpClientSpy.post.and.returnValue(of({})); - // component.http = httpClientSpy as any; - // component.agentDetails = { functions: ['func1', 'func2'] }; - // component.agentId = 'test-agent-id'; - // component.functionSelections = [true, true]; - // component.editMode = true; - // - // component.saveFunctions(); - // - // expect(component.isSavingFunctions).toBeTrue(); - // }); - // - // describe('extractFunctionCallHistory', () => { - // it('should extract function call history from user prompt text', () => { - // const userPromptText = - // 'Some text Function call history content more text'; - // const extracted = component.extractFunctionCallHistory(userPromptText); - // expect(extracted).toBe('Function call history content'); - // }); - // - // it('should return null if no function call history is present', () => { - // const userPromptText = 'Some text without function call history'; - // const extracted = component.extractFunctionCallHistory(userPromptText); - // expect(extracted).toBeNull(); - // }); - // - // it('should handle multiple function call history tags correctly', () => { - // const userPromptText = - // 'Text First call Text Second call'; - // const extracted = component.extractFunctionCallHistory(userPromptText); - // expect(extracted).toBe('First call'); - // }); - // }); -}); diff --git a/frontend/src/app/agent/agent.component.ts b/frontend/src/app/agent/agent.component.ts deleted file mode 100644 index cd7ba3f5..00000000 --- a/frontend/src/app/agent/agent.component.ts +++ /dev/null @@ -1,545 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; -import { HttpClient } from '@angular/common/http'; -import { map } from 'rxjs/operators'; -import { FormBuilder, FormGroup, Validators } from '@angular/forms'; -import { environment } from '@env/environment'; -import { MatSnackBar } from '@angular/material/snack-bar'; -import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; -import { AgentContext, AgentRunningState } from '@app/agents/agents.component'; -import { catchError, finalize } from 'rxjs/operators'; -import { of, throwError } from 'rxjs'; -import { MatDialog } from '@angular/material/dialog'; -import { FunctionEditModalComponent } from './function-edit-modal/function-edit-modal.component'; -import { ResumeAgentModalComponent } from './resume-agent-modal/resume-agent-modal.component'; - -export interface LlmCall { - // LlmRequest fields - /** UUID */ - id: string; - /** From the GenerateTextOptions.id field */ - description?: string; - systemPrompt?: string; - userPrompt: string; - /** Populated when called by an agent */ - agentId?: string; - /** Populated when called by a user through the UI */ - userId?: string; - callStack?: string; - /** LLM service/model identifier */ - llmId: string; - /** Time of the LLM request */ - requestTime: number; - - // LlmResponse fields - responseText?: string; - /** Duration in millis until the first response from the LLM */ - timeToFirstToken?: number; - /** Duration in millis for the full response */ - totalTime?: number; - /** Cost in $USD */ - cost?: number; - inputTokens: number; - outputTokens: number; - - // UI state field - responseTextExpanded: boolean; - userPromptExpanded: boolean; -} - -@Component({ - selector: 'app-agent', - templateUrl: './agent.component.html', - styleUrls: ['./agent.component.scss'], -}) -export class AgentComponent implements OnInit { - llms: Array<{ id: string; name: string }> = []; - llmCalls: LlmCall[] = []; - agentId: string | null = null; - llmNameMap: Map = new Map(); - llmCallSystemPromptOpenState: boolean[] = []; - llmCallFunctionCallsOpenState: boolean[] = []; - llmCallMemoryOpenState: boolean[] = []; - agentDetails: AgentContext | null = null; - selectedTabIndex: number = 0; - feedbackForm!: FormGroup; - hilForm!: FormGroup; - errorForm!: FormGroup; - resumeForm!: FormGroup; - functionsForm!: FormGroup; - output: string | null = null; - isSubmitting: boolean = false; - isResumingError: boolean = false; - allFunctions: string[] = []; - - userPromptExpanded: boolean = false; - systemPromptExpanded: boolean = false; - functionCallHistoryExpanded: boolean = false; - memoryContentsExpanded: boolean = false; - outputExpanded: boolean = false; - - editMode: boolean = false; - functionSelections: boolean[] = []; - isSavingFunctions: boolean = false; - - constructor( - private route: ActivatedRoute, - private http: HttpClient, - private formBuilder: FormBuilder, - private snackBar: MatSnackBar, - private router: Router, - private sanitizer: DomSanitizer, - private dialog: MatDialog - ) {} - - ngOnInit(): void { - // Check if there's a tab name in the URL - const fragment = this.route.snapshot.fragment; - if (fragment) { - const tabIndex = this.getTabIndexFromFragment(fragment); - if (tabIndex !== -1) { - this.selectedTabIndex = tabIndex; - } else { - this.selectedTabIndex = 0; // Default to the first tab if the fragment is invalid - } - } else { - this.selectedTabIndex = 0; // Default to the first tab if no fragment is present - } - this.route.paramMap.pipe(map((params) => params.get('agentId'))).subscribe((agentId) => { - this.agentId = agentId; - if (agentId) { - this.loadAgentDetails(agentId); - } - this.loadLlmCalls(); - }); - this.initializeFeedbackForm(); - this.initializeErrorForm(); - this.initializeHillForm(); - this.http - .get<{ data: Array<{ id: string; name: string }> }>(`${environment.serverUrl}/llms/list`) - .pipe( - map((response) => { - console.log(response); - return response.data as Array<{ id: string; name: string }>; - }) - ) - .subscribe((llms) => { - this.llms = llms; - this.llmNameMap = new Map(llms.map((llm) => [llm.id, llm.name])); - }); - - this.http - .get<{ data: string[] }>(`${environment.serverUrl}/agent/v1/functions`) - .pipe( - map((response) => { - return (response.data as string[]).filter((name) => name !== 'Agent'); - }) - ) - .subscribe((functions) => { - this.allFunctions = functions.sort(); - }); - } - - private getTabNameFromIndex(index: number): string { - switch (index) { - case 0: - return 'details'; - case 1: - return 'memory'; - case 2: - return 'function-calls'; - case 3: - return 'llm-calls'; - default: - return 'details'; - } - } - - private getTabIndexFromFragment(fragment: string): number { - switch (fragment) { - case 'details': - return 0; - case 'memory': - return 1; - case 'function-calls': - return 2; - case 'llm-calls': - return 3; - default: - return -1; - } - } - - onTabChange(index: number): void { - this.selectedTabIndex = index; - // Update the URL fragment with the current tab name - const tabName = this.getTabNameFromIndex(index); - this.router.navigate([], { fragment: tabName }).catch(console.error); - } - - private initializeFeedbackForm(): void { - this.feedbackForm = this.formBuilder.group({ - feedback: ['', Validators.required], - }); - } - - private initializeHillForm(): void { - this.hilForm = this.formBuilder.group({ - feedback: [''], - }); - } - - private initializeErrorForm(): void { - this.errorForm = this.formBuilder.group({ - errorDetails: ['', Validators.required], - }); - } - - displayState(state: AgentRunningState): string { - switch (state) { - case 'agent': - return 'Agent control loop'; - case 'functions': - return 'Calling functions'; - case 'error': - return 'Error'; - case 'hil': - return 'Human-in-the-loop check'; - case 'feedback': - return 'Agent requested feedback'; - case 'completed': - return 'Completed'; - default: - return state; - } - } - - onResumeHil(): void { - if (!this.hilForm.valid) return; - this.isSubmitting = true; - const feedback = this.hilForm.get('feedback')?.value; - this.http - .post(`${environment.serverUrl}/agent/v1/resume-hil`, { - agentId: this.agentId, - executionId: this.agentDetails?.executionId, - feedback, - }) - .pipe( - catchError((error) => { - console.error('Error resuming agent:', error); - this.snackBar.open('Error resuming agent', 'Close', { duration: 3000 }); - this.isSubmitting = false; - return of(null); - }) - ) - .subscribe({ - next: (response) => { - if (response) { - console.log('Agent resumed successfully:', response); - this.snackBar.open('Agent resumed successfully', 'Close', { duration: 3000 }); - this.loadAgentDetails(this.agentId!); - this.loadLlmCalls(); - this.hilForm.reset(); - } - this.isSubmitting = false; - }, - }); - } - - openResumeModal(): void { - const dialogRef = this.dialog.open(ResumeAgentModalComponent, { - width: '500px', - }); - - dialogRef.afterClosed().subscribe((result) => { - if (result) { - this.resumeCompletedAgent(result.resumeInstructions); - } - }); - } - - private resumeCompletedAgent(resumeInstructions: string): void { - this.isSubmitting = true; - this.http - .post(`${environment.serverUrl}/agent/v1/resume-completed`, { - agentId: this.agentId, - executionId: this.agentDetails?.executionId, - instructions: resumeInstructions, - }) - .pipe( - catchError((error) => { - console.error('Error resuming completed agent:', error); - this.snackBar.open('Error resuming completed agent', 'Close', { duration: 3000 }); - return of(null); - }), - finalize(() => { - this.isSubmitting = false; - }) - ) - .subscribe({ - next: (response) => { - if (response) { - console.log('Agent resumed successfully:', response); - this.snackBar.open('Agent resumed successfully', 'Close', { duration: 3000 }); - this.loadAgentDetails(this.agentId!); - this.loadLlmCalls(); - } - }, - }); - } - - onResumeError(): void { - if (!this.errorForm.valid) return; - this.isResumingError = true; - const errorDetails = this.errorForm.get('errorDetails')?.value; - this.http - .post(`${environment.serverUrl}/agent/v1/resume-error`, { - agentId: this.agentId, - executionId: this.agentDetails?.executionId, - feedback: errorDetails, - }) - .pipe( - catchError((error) => { - console.error('Error resuming agent:', error); - this.snackBar.open('Error resuming agent', 'Close', { duration: 3000 }); - this.isResumingError = false; - return of(null); - }) - ) - .subscribe({ - next: (response) => { - if (response) { - console.log('Agent resumed successfully:', response); - this.snackBar.open('Agent resumed successfully', 'Close', { duration: 3000 }); - this.loadAgentDetails(this.agentId!); - this.loadLlmCalls(); - this.errorForm.reset(); - } - this.isResumingError = false; - }, - }); - } - - cancelAgent(): void { - this.http - .post(`${environment.serverUrl}/agent/v1/cancel`, { - agentId: this.agentId, - executionId: this.agentDetails?.executionId, - reason: 'None provided', - }) - .pipe( - catchError((error) => { - console.error('Error cancelling agent:', error); - this.snackBar.open('Error cancelling agent', 'Close', { duration: 3000 }); - return of(null); - }) - ) - .subscribe({ - next: (response) => { - if (response) { - console.log('Agent cancelled successfully:', response); - this.snackBar.open('Agent cancelled successfully', 'Close', { duration: 3000 }); - this.loadAgentDetails(this.agentId!); - } - }, - }); - } - - onSubmitFeedback(): void { - if (!this.feedbackForm.valid) return; - const feedback = this.feedbackForm.get('feedback')?.value; - this.http - .post(`${environment.serverUrl}/agent/v1/feedback`, { - agentId: this.agentId, - executionId: this.agentDetails?.executionId, - feedback: feedback, - }) - .pipe( - catchError((error) => { - console.error('Error submitting feedback:', error); - this.snackBar.open('Error submitting feedback', 'Close', { duration: 3000 }); - return of(null); - }) - ) - .subscribe({ - next: (response) => { - if (response) { - console.log('Feedback submitted successfully:', response); - this.snackBar.open('Feedback submitted successfully', 'Close', { duration: 3000 }); - this.loadAgentDetails(this.agentId!); - this.loadLlmCalls(); - this.feedbackForm.reset(); - } - }, - }); - } - - loadLlmCalls(): void { - if (this.agentId) { - this.http - .get(`${environment.serverUrl}/llms/calls/agent/${this.agentId}`) - .pipe( - catchError((error) => { - console.error('Error loading LLM calls', error); - this.snackBar.open('Error loading LLM calls', 'Close', { duration: 3000 }); - return of(null); - }) - ) - .subscribe((calls) => { - if (calls) { - this.llmCalls = calls.data; - this.llmCalls.forEach((call) => { - call.userPrompt = call.userPrompt.replace('\\n', '
'); - if (call.systemPrompt) call.systemPrompt = call.systemPrompt.replace('\\n', '
'); - }); - } - }); - } - } - - removeFunctionCallHistory(text: string): string { - return text.replace(/.*?<\/function_call_history>/gs, ''); - } - - private loadAgentDetails(agentId: string): void { - this.http - .get(`${environment.serverUrl}/agent/v1/details/${agentId}`) - .pipe( - catchError((error) => { - console.error('Error loading agent details', error); - this.snackBar.open('Error loading agent details', 'Close', { duration: 3000 }); - return of(null); - }) - ) - .subscribe((details) => { - if (details) { - this.agentDetails = details.data as AgentContext; - this.output = null; - if (this.agentDetails && this.agentDetails.state === 'completed') { - // If the agent has been cancelled after an error then display the error - // Otherwise display the Agent_completed argument - const maybeCompletedFunctionCall = this.agentDetails.functionCallHistory.length - ? this.agentDetails.functionCallHistory.slice(-1)[0] - : null; - if (maybeCompletedFunctionCall && maybeCompletedFunctionCall.parameters['note']) - this.output = this.agentDetails.error ?? maybeCompletedFunctionCall?.parameters['note'] ?? ''; - } - // Initialize expanded states for stdout and stderr - this.agentDetails?.functionCallHistory.forEach((invoked: any) => { - invoked.stdoutExpanded = false; - invoked.stderrExpanded = false; - }); - - // Initialize function selections - this.functionSelections = this.agentDetails.functions.map(() => true) ?? []; - } - }); - } - - refreshAgentDetails(): void { - if (this.agentId) { - this.loadAgentDetails(this.agentId); - this.loadLlmCalls(); - } - } - - keys(obj: any) { - return Object.keys(obj); - } - - extractMemoryContent(text: string): string | null { - const memoryContentRegex = /(.*?)<\/memory>/s; - const match: RegExpExecArray | null = memoryContentRegex.exec(text); - if (match && match[0]) { - return match[0].trim(); - } - return null; - } - - removeMemoryContent(text: string): string { - return text.replace(/.*?<\/memory>/gs, ''); - } - - extractFunctionCallHistory(text: string): string | null { - const functionCallHistoryRegex = /(.*?)<\/function_call_history>/s; - const match = functionCallHistoryRegex.exec(text); - if (match && match[1]) { - return match[1].trim(); - } - return null; - } - - convertNewlinesToHtml(text: string): SafeHtml { - text ??= ''; - // sanitize first? - return this.sanitizer.bypassSecurityTrustHtml( - text.replaceAll('\\n', '
').replaceAll('\\t', '    ') - ); - } - - agentUrl(agent: AgentContext): string { - return `https://console.cloud.google.com/firestore/databases/${ - environment.firestoreDb || '(default)' - }/data/panel/AgentContext/${agent.agentId}?project=${environment.gcpProject}`; - } - - llmCallUrl(llmCall: LlmCall): string { - return `https://console.cloud.google.com/firestore/databases/${ - environment.firestoreDb || '(default)' - }/data/panel/LlmCall/${llmCall.id}?project=${environment.gcpProject}`; - } - - traceUrl(agent: AgentContext): string { - return `https://console.cloud.google.com/traces/list?referrer=search&project=${environment.gcpProject}&supportedpurview=project&pageState=(%22traceIntervalPicker%22:(%22groupValue%22:%22P1D%22,%22customValue%22:null))&tid=${agent.traceId}`; - } - - getLlmName(llmId: string): string { - return this.llmNameMap.get(llmId) || llmId; - } - - openFunctionEditModal() { - const dialogRef = this.dialog.open(FunctionEditModalComponent, { - width: '400px', - data: { - functions: this.agentDetails!.functions, - allFunctions: this.allFunctions, - }, - }); - - dialogRef.afterClosed().subscribe((result) => { - if (result) { - this.saveFunctions(result); - } - }); - } - - saveFunctions(selectedFunctions: string[]) { - if (!this.agentDetails || !this.agentId) { - this.snackBar.open('No agent selected', 'Close', { duration: 3000 }); - return; - } - - this.isSavingFunctions = true; - this.http - .post(`${environment.serverUrl}/agent/v1/update-functions`, { - agentId: this.agentId, - functions: selectedFunctions, - }) - .pipe( - catchError((error) => { - console.error('Error updating agent functions:', error); - this.snackBar.open('Error updating agent functions', 'Close', { duration: 3000 }); - return throwError(() => new Error('Error updating agent functions')); - }), - finalize(() => { - this.isSavingFunctions = false; - }) - ) - .subscribe({ - next: () => { - this.snackBar.open('Agent functions updated successfully', 'Close', { duration: 3000 }); - this.loadAgentDetails(this.agentId!); - }, - }); - } -} diff --git a/frontend/src/app/agent/agent.module.ts b/frontend/src/app/agent/agent.module.ts deleted file mode 100644 index 02d1e36c..00000000 --- a/frontend/src/app/agent/agent.module.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { TranslateModule } from '@ngx-translate/core'; -import { FlexLayoutModule } from '@angular/flex-layout'; -import { ReactiveFormsModule, FormsModule } from '@angular/forms'; - -import { MaterialModule } from '@app/material.module'; -import { AgentRoutingModule } from './agent-routing.module'; -import { AgentComponent } from './agent.component'; -import { MatIconModule } from '@angular/material/icon'; -import { MatListModule } from '@angular/material/list'; -import { MatDialogModule } from '@angular/material/dialog'; -import { FunctionEditModalComponent } from './function-edit-modal/function-edit-modal.component'; -import { ResumeAgentModalComponent } from './resume-agent-modal/resume-agent-modal.component'; - -@NgModule({ - imports: [ - CommonModule, - TranslateModule, - FlexLayoutModule, - MaterialModule, - AgentRoutingModule, - MatIconModule, - MatListModule, - MatDialogModule, - ReactiveFormsModule, - FormsModule, - ], - declarations: [AgentComponent, FunctionEditModalComponent, ResumeAgentModalComponent], -}) -export class AgentModule {} diff --git a/frontend/src/app/agent/resume-agent-modal/resume-agent-modal.component.html b/frontend/src/app/agent/resume-agent-modal/resume-agent-modal.component.html deleted file mode 100644 index 71036363..00000000 --- a/frontend/src/app/agent/resume-agent-modal/resume-agent-modal.component.html +++ /dev/null @@ -1,18 +0,0 @@ -

Resume Completed Agent

- -
- - - -
-
- - - - diff --git a/frontend/src/app/agent/resume-agent-modal/resume-agent-modal.component.scss b/frontend/src/app/agent/resume-agent-modal/resume-agent-modal.component.scss deleted file mode 100644 index 482ed5e1..00000000 --- a/frontend/src/app/agent/resume-agent-modal/resume-agent-modal.component.scss +++ /dev/null @@ -1,7 +0,0 @@ -.full-width { - width: 100%; -} - -.mat-mdc-form-field { - width: 100%; -} diff --git a/frontend/src/app/agent/resume-agent-modal/resume-agent-modal.component.ts b/frontend/src/app/agent/resume-agent-modal/resume-agent-modal.component.ts deleted file mode 100644 index 7ff9ad90..00000000 --- a/frontend/src/app/agent/resume-agent-modal/resume-agent-modal.component.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Component, Inject } from '@angular/core'; -import { FormBuilder, FormGroup } from '@angular/forms'; -import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; - -@Component({ - selector: 'app-resume-agent-modal', - templateUrl: './resume-agent-modal.component.html', - styleUrls: ['./resume-agent-modal.component.scss'], -}) -export class ResumeAgentModalComponent { - resumeForm: FormGroup; - - constructor( - private formBuilder: FormBuilder, - public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: any - ) { - this.resumeForm = this.formBuilder.group({ - resumeInstructions: [''], - }); - } - - onSubmit(): void { - if (this.resumeForm.valid) { - this.dialogRef.close(this.resumeForm.value); - } - } - - onCancel(): void { - this.dialogRef.close(); - } -} diff --git a/frontend/src/app/agents/agents-routing.module.ts b/frontend/src/app/agents/agents-routing.module.ts deleted file mode 100644 index 3fb58ba6..00000000 --- a/frontend/src/app/agents/agents-routing.module.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { NgModule } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; -import { marker } from '@biesbjerg/ngx-translate-extract-marker'; - -import { AgentsComponent } from './agents.component'; - -const routes: Routes = [ - // Module is lazy loaded, see app-routing.module.ts - { path: '', component: AgentsComponent, data: { title: marker('Agents') } }, -]; - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule], - providers: [], -}) -export class AgentsRoutingModule {} diff --git a/frontend/src/app/agents/agents.component.html b/frontend/src/app/agents/agents.component.html deleted file mode 100644 index 070759ea..00000000 --- a/frontend/src/app/agents/agents.component.html +++ /dev/null @@ -1,70 +0,0 @@ -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - Name - {{ element.name }} - State{{ element.state }}User Prompt{{ element.userPrompt | slice : 0 : 150 }}System Prompt{{ element.systemPrompt }}Error/Completed Output - {{ (element.state === 'error' ? element.error : element.completed) | slice : 0 : 150 }} - Cost{{ element.cost | number : '1.2-2' }}
-
diff --git a/frontend/src/app/agents/agents.component.scss b/frontend/src/app/agents/agents.component.scss deleted file mode 100644 index 07a71729..00000000 --- a/frontend/src/app/agents/agents.component.scss +++ /dev/null @@ -1,17 +0,0 @@ -td.mat-cell, -th.mat-header-cell { - padding: 0 16px; -} -th.mat-header-cell.user-prompt, -td.mat-cell.user-prompt { - min-width: 100px; -} -.table-actions { - padding: 16px; - display: flex; - justify-content: flex-end; -} - -.mat-column-select { - overflow: initial; -} diff --git a/frontend/src/app/agents/agents.component.spec.ts b/frontend/src/app/agents/agents.component.spec.ts deleted file mode 100644 index 750d65c0..00000000 --- a/frontend/src/app/agents/agents.component.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { AgentsComponent } from './agents.component'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { RouterTestingModule } from '@angular/router/testing'; -import { ReactiveFormsModule } from '@angular/forms'; -import { MaterialModule } from '@app/material.module'; - -describe('AgentsComponent', () => { - let component: AgentsComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, RouterTestingModule, ReactiveFormsModule, MaterialModule], - declarations: [AgentsComponent], - }).compileComponents(); - - fixture = TestBed.createComponent(AgentsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/frontend/src/app/agents/agents.component.ts b/frontend/src/app/agents/agents.component.ts deleted file mode 100644 index e3863e6b..00000000 --- a/frontend/src/app/agents/agents.component.ts +++ /dev/null @@ -1,183 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { SelectionModel } from '@angular/cdk/collections'; -import { MatSnackBar } from '@angular/material/snack-bar'; -import { HttpClient } from '@angular/common/http'; -import { filter, map } from 'rxjs/operators'; -import { MatTableDataSource } from '@angular/material/table'; -import { environment } from '@env/environment'; -import { AgentType } from '@shared'; - -export type TaskLevel = 'easy' | 'medium' | 'hard' | 'xhard'; - -interface LLM { - /** - * The LLM model identifier - */ - getModel(): string; - - getService(): string; -} - -/** - * The LLMs for each Task Level - */ -export type AgentLLMs = Record; - -export interface FunctionCall { - function_name: string; - parameters: { [key: string]: any }; -} - -export interface FunctionCallResult extends FunctionCall { - stdout?: string; - stderr?: string; - - stdoutExpanded: boolean; - stdoutSummary?: string; - stderrExpanded: boolean; - stderrSummary?: string; -} - -/** - * agent - waiting for the agent LLM call(s) to generate control loop update - * functions - waiting for the planned function call(s) to complete - * error - the agent control loop has errored - * hil - deprecated for humanInLoop_agent and humanInLoop_tool - * hitl_threshold - If the agent has reached budget or iteration thresholds. At this point the agent is not executing any LLM/function calls. - * hitl_tool - When a function has request HITL in the function calling part of the control loop - * hitl_feedback - the agent has requested human feedback for a decision. At this point the agent is not executing any LLM/function calls. - * hil - deprecated version of hitl_feedback - * feedback - deprecated version of hitl_feedback - * child_agents - waiting for child agents to complete - * completed - the agent has called the completed function. - * shutdown - if the agent has been instructed by the system to pause (e.g. for server shutdown) - * timeout - for chat agents when there hasn't been a user input for a configured amount of time - */ -export type AgentRunningState = - | 'agent' - | 'functions' - | 'error' - | 'hil' - | 'hitl_threshold' - | 'hitl_tool' - | 'feedback' - | 'hitl_feedback' - | 'completed' - | 'shutdown' - | 'child_agents' - | 'timeout'; - -export interface AgentContext { - /** Agent instance id - allocated when the agent is first starts */ - agentId: string; - /** Id of the running execution. This changes after the control loop restarts after an exit due to pausing, human in loop etc */ - executionId: string; - traceId: string; - name: string; - parentAgentId?: string; - isRetry: boolean; - /** Empty string in single-user mode */ - userId: string; - userEmail?: string; - type: AgentType; - state: AgentRunningState; - inputPrompt: string; - userPrompt: string; - systemPrompt: string; - functionCallHistory: FunctionCallResult[]; - - // These three fields are mutable for when saving state as the agent does work - error?: string; - planningResponse?: string; - invoking: FunctionCall[]; - /** Total cost of running this agent */ - cost: number; - /** Budget allocated until human intervention is required. This may be increased when the agent is running */ - budget: number; - /** Budget remaining until human intervention is required */ - budgetRemaining: number; - - llms: { easy: string; medium: string; hard: string; xhard: string }; - - /** Working filesystem */ - fileSystem: { workingDirectory: string }; - /** The functions available to the agent */ - functions: string[]; - /** Memory persisted over the agent's control loop iterations */ - memory: Map; -} - -@Component({ - selector: 'app-contexts', - templateUrl: './agents.component.html', - styleUrls: ['./agents.component.scss'], -}) -export class AgentsComponent implements OnInit { - agentContexts$: MatTableDataSource = new MatTableDataSource([]); - selection = new SelectionModel(true, []); - - displayedColumns: string[] = [ - 'select', - 'name', - 'state', - 'userPrompt', - //'systemPrompt', - 'output', - 'cost', - ]; - - constructor(private http: HttpClient, private snackBar: MatSnackBar) {} - - ngOnInit(): void { - this.loadAgentContexts(); - } - - loadAgentContexts(showReloadToast: boolean = false): void { - const sub = this.http - .get<{ data: AgentContext[] }>(`${environment.serverUrl}/agent/v1/list`) - .pipe( - filter((contexts) => contexts !== null), - map((contexts) => contexts.data) - ) - .subscribe((contexts) => { - this.snackBar.open('Agents refreshed', 'Close', { duration: 1000 }); - this.agentContexts$.data = contexts; - this.selection.clear(); - }); - } - - isAllSelected() { - const numSelected = this.selection.selected.length; - const numRows = this.agentContexts$.data.length; - return numSelected === numRows; - } - - masterToggle() { - this.isAllSelected() - ? this.selection.clear() - : this.agentContexts$.data.forEach((row) => this.selection.select(row)); - } - - deleteSelectedAgents() { - const selectedAgentIds = this.selection.selected.map((agent) => agent.agentId); - if (selectedAgentIds.length === 0) { - this.snackBar.open('No agents selected for deletion', 'Close', { duration: 3000 }); - return; - } - - this.http.post(`${environment.serverUrl}/agent/v1/delete`, { agentIds: selectedAgentIds }).subscribe({ - next: () => { - this.snackBar.open('Agents deleted successfully', 'Close', { duration: 3000 }); - this.loadAgentContexts(); - }, - error: (error) => { - console.error('Error deleting agents:', error); - this.snackBar.open('Error deleting agents', 'Close', { duration: 3000 }); - }, - }); - } - - refreshAgents() { - this.loadAgentContexts(true); - } -} diff --git a/frontend/src/app/agents/agents.module.ts b/frontend/src/app/agents/agents.module.ts deleted file mode 100644 index 5d9e6873..00000000 --- a/frontend/src/app/agents/agents.module.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { TranslateModule } from '@ngx-translate/core'; -import { FlexLayoutModule } from '@angular/flex-layout'; - -import { MaterialModule } from '@app/material.module'; -import { AgentsRoutingModule } from './agents-routing.module'; -import { AgentsComponent } from './agents.component'; - -@NgModule({ - imports: [CommonModule, TranslateModule, FlexLayoutModule, MaterialModule, AgentsRoutingModule], - declarations: [AgentsComponent], -}) -export class AgentsModule {} diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts deleted file mode 100644 index ca33db48..00000000 --- a/frontend/src/app/app-routing.module.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { NgModule } from '@angular/core'; -import { Routes, RouterModule, PreloadAllModules } from '@angular/router'; -import { Shell } from '@app/shell/shell.service'; - -const routes: Routes = [ - Shell.childRoutes([{ path: 'about', loadChildren: () => import('./about/about.module').then((m) => m.AboutModule) }]), - Shell.childRoutes([ - { path: 'agents', loadChildren: () => import('./agents/agents.module').then((m) => m.AgentsModule) }, - ]), - Shell.childRoutes([{ path: 'agent', loadChildren: () => import('./agent/agent.module').then((m) => m.AgentModule) }]), - Shell.childRoutes([ - { path: 'runAgent', loadChildren: () => import('./runAgent/runAgent.module').then((m) => m.RunAgentModule) }, - ]), - Shell.childRoutes([ - { path: 'profile', loadChildren: () => import('./profile/profile.module').then((m) => m.ProfileModule) }, - ]), - Shell.childRoutes([{ path: 'chat', loadChildren: () => import('./chat/chat.module').then((m) => m.ChatModule) }]), - Shell.childRoutes([ - { - path: 'code-reviews', - loadChildren: () => import('./code-review/code-review.module').then((m) => m.CodeReviewModule), - }, - ]), - Shell.childRoutes([{ path: 'code', loadChildren: () => import('./code/code.module').then((m) => m.CodeModule) }]), - // Fallback when no prior route is matched - { path: '**', redirectTo: '', pathMatch: 'full' }, -]; - -@NgModule({ - imports: [RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })], - exports: [RouterModule], - providers: [], -}) -export class AppRoutingModule {} diff --git a/frontend/src/app/app.component.scss b/frontend/src/app/app.component.scss index 2453e291..1d561241 100644 --- a/frontend/src/app/app.component.scss +++ b/frontend/src/app/app.component.scss @@ -1,4 +1,6 @@ :host { - display: flex; - flex: 1; + display: flex; + flex: 1 1 auto; + width: 100%; + height: 100%; } diff --git a/frontend/src/app/app.component.spec.ts b/frontend/src/app/app.component.spec.ts deleted file mode 100644 index dd9687a9..00000000 --- a/frontend/src/app/app.component.spec.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { TestBed, waitForAsync } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; -import { TranslateModule } from '@ngx-translate/core'; - -import { AppComponent } from './app.component'; - -describe('AppComponent', () => { - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [RouterTestingModule, TranslateModule.forRoot()], - declarations: [AppComponent], - providers: [], - }).compileComponents(); - })); - - it('should create the app', waitForAsync(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.debugElement.componentInstance; - expect(app).toBeTruthy(); - }), 30000); -}); diff --git a/frontend/src/app/app.component.ts b/frontend/src/app/app.component.ts index f49073a1..e1c10ba2 100644 --- a/frontend/src/app/app.component.ts +++ b/frontend/src/app/app.component.ts @@ -1,67 +1,16 @@ -import { Component, OnInit, OnDestroy } from '@angular/core'; -import { Router, NavigationEnd, ActivatedRoute } from '@angular/router'; -import { Title } from '@angular/platform-browser'; -import { TranslateService } from '@ngx-translate/core'; -import { merge } from 'rxjs'; -import { filter, map, switchMap } from 'rxjs/operators'; +import { Component } from '@angular/core'; +import { RouterOutlet } from '@angular/router'; -import { environment } from '@env/environment'; -import { Logger, UntilDestroy, untilDestroyed } from '@shared'; -import { I18nService } from '@app/i18n'; - -const log = new Logger('App'); - -@UntilDestroy() @Component({ - selector: 'app-root', - templateUrl: './app.component.html', - styleUrls: ['./app.component.scss'], + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.scss'], + standalone: true, + imports: [RouterOutlet], }) -export class AppComponent implements OnInit, OnDestroy { - constructor( - private router: Router, - private activatedRoute: ActivatedRoute, - private titleService: Title, - private translateService: TranslateService, - private i18nService: I18nService - ) {} - - ngOnInit() { - // Setup logger - if (environment.production) { - Logger.enableProductionMode(); - } - - log.debug('init'); - - // Setup translations - this.i18nService.init(environment.defaultLanguage, environment.supportedLanguages); - - const onNavigationEnd = this.router.events.pipe(filter((event) => event instanceof NavigationEnd)); - - // Change page title on navigation or language change, based on route data - merge(this.translateService.onLangChange, onNavigationEnd) - .pipe( - map(() => { - let route = this.activatedRoute; - while (route.firstChild) { - route = route.firstChild; - } - return route; - }), - filter((route) => route.outlet === 'primary'), - switchMap((route) => route.data), - untilDestroyed(this) - ) - .subscribe((event) => { - const title = event['title']; - if (title) { - this.titleService.setTitle(this.translateService.instant(title)); - } - }); - } - - ngOnDestroy() { - this.i18nService.destroy(); - } +export class AppComponent { + /** + * Constructor + */ + constructor() {} } diff --git a/frontend/src/app/app.config.ts b/frontend/src/app/app.config.ts new file mode 100644 index 00000000..e9a1b7fb --- /dev/null +++ b/frontend/src/app/app.config.ts @@ -0,0 +1,138 @@ +import {provideHttpClient, HTTP_INTERCEPTORS, withInterceptorsFromDi} from '@angular/common/http'; +import { APP_INITIALIZER, ApplicationConfig, inject } from '@angular/core'; +import { BaseUrlInterceptor } from './core/interceptors/base-url.interceptor'; +import { LuxonDateAdapter } from '@angular/material-luxon-adapter'; +import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core'; +import { provideAnimations } from '@angular/platform-browser/animations'; +import { + PreloadAllModules, + provideRouter, + withInMemoryScrolling, + withPreloading, +} from '@angular/router'; +import { provideFuse } from '@fuse'; +import { TranslocoService, provideTransloco } from '@ngneat/transloco'; +import { appRoutes } from 'app/app.routes'; +import { provideAuth } from 'app/core/auth/auth.provider'; +import { provideIcons } from 'app/core/icons/icons.provider'; +import { mockApiServices } from 'app/mock-api'; +import { firstValueFrom } from 'rxjs'; +import { TranslocoHttpLoader } from './core/transloco/transloco.http-loader'; + +export const appConfig: ApplicationConfig = { + providers: [ + provideAnimations(), + provideHttpClient(withInterceptorsFromDi()), + { + provide: HTTP_INTERCEPTORS, + useClass: BaseUrlInterceptor, + multi: true + }, + provideRouter( + appRoutes, + withPreloading(PreloadAllModules), + withInMemoryScrolling({ scrollPositionRestoration: 'enabled' }) + ), + + // Material Date Adapter + { + provide: DateAdapter, + useClass: LuxonDateAdapter, + }, + { + provide: MAT_DATE_FORMATS, + useValue: { + parse: { + dateInput: 'D', + }, + display: { + dateInput: 'DDD', + monthYearLabel: 'LLL yyyy', + dateA11yLabel: 'DD', + monthYearA11yLabel: 'LLLL yyyy', + }, + }, + }, + + // Transloco Config + provideTransloco({ + config: { + availableLangs: [ + { + id: 'en', + label: 'English', + }, + { + id: 'tr', + label: 'Turkish', + }, + ], + defaultLang: 'en', + fallbackLang: 'en', + reRenderOnLangChange: true, + prodMode: true, + }, + loader: TranslocoHttpLoader, + }), + { + // Preload the default language before the app starts to prevent empty/jumping content + provide: APP_INITIALIZER, + useFactory: () => { + const translocoService = inject(TranslocoService); + const defaultLang = translocoService.getDefaultLang(); + translocoService.setActiveLang(defaultLang); + + return () => firstValueFrom(translocoService.load(defaultLang)); + }, + multi: true, + }, + + // Fuse + provideAuth(), + provideIcons(), + provideFuse({ + mockApi: { + delay: 0, + services: mockApiServices, + }, + fuse: { + // Default UI settings + layout: 'modern', + scheme: 'light', + screens: { + sm: '600px', + md: '960px', + lg: '1280px', + xl: '1440px', + }, + theme: 'theme-brand', + themes: [ + { + id: 'theme-default', + name: 'Default', + }, + { + id: 'theme-brand', + name: 'Brand', + }, + { + id: 'theme-teal', + name: 'Teal', + }, + { + id: 'theme-rose', + name: 'Rose', + }, + { + id: 'theme-purple', + name: 'Purple', + }, + { + id: 'theme-amber', + name: 'Amber', + }, + ], + }, + }), + ], +}; diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts deleted file mode 100644 index f9dd37fa..00000000 --- a/frontend/src/app/app.module.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { BrowserModule } from '@angular/platform-browser'; -import { NgModule } from '@angular/core'; -import { FormsModule } from '@angular/forms'; -import { RouteReuseStrategy, RouterModule } from '@angular/router'; -import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http'; -import { TranslateModule } from '@ngx-translate/core'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { MaterialModule } from './material.module'; - -import { RouteReusableStrategy, ApiPrefixInterceptor, ErrorHandlerInterceptor, SharedModule } from '@shared'; -import { AuthModule } from '@app/auth'; -import { HomeModule } from './home/home.module'; -import { ShellModule } from './shell/shell.module'; -import { AppComponent } from './app.component'; -import { AppRoutingModule } from './app-routing.module'; -import { MarkdownModule } from 'ngx-markdown'; - -@NgModule({ - imports: [ - BrowserModule, - FormsModule, - HttpClientModule, - RouterModule, - TranslateModule.forRoot(), - BrowserAnimationsModule, - MaterialModule, - SharedModule, - ShellModule, - HomeModule, - AuthModule, - MarkdownModule.forRoot(), - AppRoutingModule, // must be imported as the last module as it contains the fallback route - ], - declarations: [AppComponent], - providers: [ - { - provide: HTTP_INTERCEPTORS, - useClass: ApiPrefixInterceptor, - multi: true, - }, - { - provide: HTTP_INTERCEPTORS, - useClass: ErrorHandlerInterceptor, - multi: true, - }, - { - provide: RouteReuseStrategy, - useClass: RouteReusableStrategy, - }, - ], - bootstrap: [AppComponent], -}) -export class AppModule {} diff --git a/frontend/src/app/app.resolvers.ts b/frontend/src/app/app.resolvers.ts new file mode 100644 index 00000000..e7099d6c --- /dev/null +++ b/frontend/src/app/app.resolvers.ts @@ -0,0 +1,15 @@ +import { inject } from '@angular/core'; +import { NavigationService } from 'app/core/navigation/navigation.service'; +import { NotificationsService } from 'app/layout/common/notifications/notifications.service'; +import { forkJoin } from 'rxjs'; + +export const initialDataResolver = () => { + const navigationService = inject(NavigationService); + const notificationsService = inject(NotificationsService); + + // Fork join multiple API endpoint calls to wait all of them to finish + return forkJoin([ + navigationService.get(), + notificationsService.getAll(), + ]); +}; diff --git a/frontend/src/app/app.routes.ts b/frontend/src/app/app.routes.ts new file mode 100644 index 00000000..3b145397 --- /dev/null +++ b/frontend/src/app/app.routes.ts @@ -0,0 +1,85 @@ +import { Route } from '@angular/router'; +import { initialDataResolver } from 'app/app.resolvers'; +import { AuthGuard } from 'app/core/auth/guards/auth.guard'; +import { NoAuthGuard } from 'app/core/auth/guards/noAuth.guard'; +import { LayoutComponent } from 'app/layout/layout.component'; + +// @formatter:off +/* eslint-disable max-len */ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ +export const appRoutes: Route[] = [ + + // Redirect empty path to '/example' + {path: '', pathMatch : 'full', redirectTo: 'example'}, + + // Redirect signed-in user to the '/example' + // + // After the user signs in, the sign-in page will redirect the user to the 'signed-in-redirect' + // path. Below is another redirection for that path to redirect the user to the desired + // location. This is a small convenience to keep all main routes together here on this file. + {path: 'signed-in-redirect', pathMatch : 'full', redirectTo: 'example'}, + + // Auth routes for guests + { + path: '', + canActivate: [NoAuthGuard], + canActivateChild: [NoAuthGuard], + component: LayoutComponent, + data: { + layout: 'empty' + }, + children: [ + {path: 'confirmation-required', loadChildren: () => import('app/modules/auth/confirmation-required/confirmation-required.routes')}, + {path: 'forgot-password', loadChildren: () => import('app/modules/auth/forgot-password/forgot-password.routes')}, + {path: 'reset-password', loadChildren: () => import('app/modules/auth/reset-password/reset-password.routes')}, + {path: 'sign-in', loadChildren: () => import('app/modules/auth/sign-in/sign-in.routes')}, + {path: 'sign-up', loadChildren: () => import('app/modules/auth/sign-up/sign-up.routes')} + ] + }, + + // Auth routes for authenticated users + { + path: '', + canActivate: [AuthGuard], + canActivateChild: [AuthGuard], + component: LayoutComponent, + data: { + layout: 'empty' + }, + children: [ + {path: 'sign-out', loadChildren: () => import('app/modules/auth/sign-out/sign-out.routes')}, + {path: 'unlock-session', loadChildren: () => import('app/modules/auth/unlock-session/unlock-session.routes')} + ] + }, + + // Landing routes + { + path: '', + component: LayoutComponent, + data: { + layout: 'empty' + }, + children: [ + {path: 'home', loadChildren: () => import('app/modules/landing/home/home.routes')}, + ] + }, + + // Admin routes + { + path: '', + // canActivate: [AuthGuard], // AuthGuard + // canActivateChild: [AuthGuard], // AuthGuard + component: LayoutComponent, + resolve: { + initialData: initialDataResolver + }, + children: [ + {path: 'example', loadChildren: () => import('app/modules/admin/home/home.routes')}, + {path: 'profile', loadChildren: () => import('app/modules/profile/profile.routes')}, + {path: 'apps/chat', loadChildren: () => import('app/modules/admin/apps/chat/chat.routes')}, + {path: 'agents', loadChildren: () => import('app/modules/agents/agent.routes')}, + {path: 'code-reviews', loadChildren: () => import('app/modules/code-review/code-review.routes')}, + {path: 'actions', loadChildren: () => import('app/modules/actions/actions.routes')}, + ] + } +]; diff --git a/frontend/src/app/auth/auth-routing.module.ts b/frontend/src/app/auth/auth-routing.module.ts deleted file mode 100644 index 7da15a6a..00000000 --- a/frontend/src/app/auth/auth-routing.module.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { NgModule } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; -import { marker } from '@biesbjerg/ngx-translate-extract-marker'; - -import { LoginComponent } from './login.component'; - -const routes: Routes = [{ path: 'login', component: LoginComponent, data: { title: marker('Login') } }]; - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule], - providers: [], -}) -export class AuthRoutingModule {} diff --git a/frontend/src/app/auth/auth.module.ts b/frontend/src/app/auth/auth.module.ts deleted file mode 100644 index 1ad2cdcf..00000000 --- a/frontend/src/app/auth/auth.module.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { ReactiveFormsModule } from '@angular/forms'; -import { TranslateModule } from '@ngx-translate/core'; -import { FlexLayoutModule } from '@angular/flex-layout'; - -import { SharedModule } from '@shared'; -import { MaterialModule } from '@app/material.module'; -import { I18nModule } from '@app/i18n'; -import { AuthRoutingModule } from './auth-routing.module'; -import { LoginComponent } from './login.component'; - -@NgModule({ - imports: [ - CommonModule, - ReactiveFormsModule, - TranslateModule, - SharedModule, - FlexLayoutModule, - MaterialModule, - I18nModule, - AuthRoutingModule, - ], - declarations: [LoginComponent], -}) -export class AuthModule {} diff --git a/frontend/src/app/auth/authentication.guard.spec.ts b/frontend/src/app/auth/authentication.guard.spec.ts deleted file mode 100644 index de5496bf..00000000 --- a/frontend/src/app/auth/authentication.guard.spec.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { Router, ActivatedRouteSnapshot } from '@angular/router'; - -import { CredentialsService } from './credentials.service'; -import { MockCredentialsService } from './credentials.service.mock'; -import { AuthenticationGuard } from './authentication.guard'; - -describe('AuthenticationGuard', () => { - let authenticationGuard: AuthenticationGuard; - let credentialsService: MockCredentialsService; - let mockRouter: any; - let mockSnapshot: any; - - beforeEach(() => { - mockRouter = { - navigate: jest.fn(), - }; - mockSnapshot = jest.fn(() => ({ - toString: jest.fn(), - })); - - TestBed.configureTestingModule({ - providers: [ - AuthenticationGuard, - { provide: CredentialsService, useClass: MockCredentialsService }, - { provide: Router, useValue: mockRouter }, - ], - }); - - authenticationGuard = TestBed.inject(AuthenticationGuard); - credentialsService = TestBed.inject(CredentialsService); - }); - - it('should have a canActivate method', () => { - expect(typeof authenticationGuard.canActivate).toBe('function'); - }); - - it('should return true if user is authenticated', () => { - expect(authenticationGuard.canActivate(new ActivatedRouteSnapshot(), mockSnapshot)).toBe(true); - }); - - it('should return false and redirect to login if user is not authenticated', () => { - // Arrange - credentialsService.credentials = null; - - // Act - const result = authenticationGuard.canActivate(new ActivatedRouteSnapshot(), mockSnapshot); - - // Assert - expect(mockRouter.navigate).toHaveBeenCalledWith(['/login'], { - queryParams: { redirect: undefined }, - replaceUrl: true, - }); - expect(result).toBe(false); - }); - - it('should save url as queryParam if user is not authenticated', () => { - credentialsService.credentials = null; - mockRouter.url = '/about'; - mockSnapshot.url = '/about'; - - authenticationGuard.canActivate(new ActivatedRouteSnapshot(), mockSnapshot); - expect(mockRouter.navigate).toHaveBeenCalledWith(['/login'], { - queryParams: { redirect: mockRouter.url }, - replaceUrl: true, - }); - }); -}); diff --git a/frontend/src/app/auth/authentication.guard.ts b/frontend/src/app/auth/authentication.guard.ts deleted file mode 100644 index 4a3f92ae..00000000 --- a/frontend/src/app/auth/authentication.guard.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; - -import { Logger } from '@shared'; -import { CredentialsService } from './credentials.service'; - -const log = new Logger('AuthenticationGuard'); - -@Injectable({ - providedIn: 'root', -}) -export class AuthenticationGuard implements CanActivate { - constructor(private router: Router, private credentialsService: CredentialsService) {} - - canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { - if (this.credentialsService.isAuthenticated()) { - return true; - } - - log.debug('Not authenticated, redirecting and adding redirect url...'); - this.router.navigate(['/login'], { queryParams: { redirect: state.url }, replaceUrl: true }); - return false; - } -} diff --git a/frontend/src/app/auth/authentication.service.mock.ts b/frontend/src/app/auth/authentication.service.mock.ts deleted file mode 100644 index c8e8d6cb..00000000 --- a/frontend/src/app/auth/authentication.service.mock.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Observable, of } from 'rxjs'; - -import { LoginContext } from './authentication.service'; -import { Credentials } from './credentials.service'; - -export class MockAuthenticationService { - credentials: Credentials | null = { - username: 'test', - token: '123', - }; - - login(context: LoginContext): Observable { - return of({ - username: context.username, - token: '123456', - }); - } - - logout(): Observable { - this.credentials = null; - return of(true); - } -} diff --git a/frontend/src/app/auth/authentication.service.spec.ts b/frontend/src/app/auth/authentication.service.spec.ts deleted file mode 100644 index 9ce1dfc1..00000000 --- a/frontend/src/app/auth/authentication.service.spec.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { TestBed, fakeAsync, tick } from '@angular/core/testing'; - -import { AuthenticationService } from './authentication.service'; -import { CredentialsService, Credentials } from './credentials.service'; -import { MockCredentialsService } from './credentials.service.mock'; - -describe('AuthenticationService', () => { - let authenticationService: AuthenticationService; - let credentialsService: MockCredentialsService; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [{ provide: CredentialsService, useClass: MockCredentialsService }, AuthenticationService], - }); - - authenticationService = TestBed.inject(AuthenticationService); - credentialsService = TestBed.inject(CredentialsService); - credentialsService.credentials = null; - jest.spyOn(credentialsService, 'setCredentials'); - }); - - describe('login', () => { - it('should return credentials', fakeAsync(() => { - // Act - const request = authenticationService.login({ - username: 'toto', - password: '123', - }); - tick(); - - // Assert - request.subscribe((credentials) => { - expect(credentials).toBeDefined(); - expect(credentials.token).toBeDefined(); - }); - })); - - it('should authenticate user', fakeAsync(() => { - expect(credentialsService.isAuthenticated()).toBe(false); - - // Act - const request = authenticationService.login({ - username: 'toto', - password: '123', - }); - tick(); - - // Assert - request.subscribe(() => { - expect(credentialsService.isAuthenticated()).toBe(true); - expect(credentialsService.credentials).not.toBeNull(); - expect((credentialsService.credentials as Credentials).token).toBeDefined(); - expect((credentialsService.credentials as Credentials).token).not.toBeNull(); - }); - })); - - it('should persist credentials for the session', fakeAsync(() => { - // Act - const request = authenticationService.login({ - username: 'toto', - password: '123', - }); - tick(); - - // Assert - request.subscribe(() => { - expect(credentialsService.setCredentials).toHaveBeenCalled(); - expect((credentialsService.setCredentials as jest.Mock).mock.calls[0][1]).toBe(undefined); - }); - })); - - it('should persist credentials across sessions', fakeAsync(() => { - // Act - const request = authenticationService.login({ - username: 'toto', - password: '123', - remember: true, - }); - tick(); - - // Assert - request.subscribe(() => { - expect(credentialsService.setCredentials).toHaveBeenCalled(); - expect((credentialsService.setCredentials as jest.Mock).mock.calls[0][1]).toBe(true); - }); - })); - }); - - describe('logout', () => { - it('should clear user authentication', fakeAsync(() => { - // Arrange - const loginRequest = authenticationService.login({ - username: 'toto', - password: '123', - }); - tick(); - - // Assert - loginRequest.subscribe(() => { - expect(credentialsService.isAuthenticated()).toBe(true); - - const request = authenticationService.logout(); - tick(); - - request.subscribe(() => { - expect(credentialsService.isAuthenticated()).toBe(false); - expect(credentialsService.credentials).toBeNull(); - }); - }); - })); - }); -}); diff --git a/frontend/src/app/auth/authentication.service.ts b/frontend/src/app/auth/authentication.service.ts deleted file mode 100644 index 04d81205..00000000 --- a/frontend/src/app/auth/authentication.service.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Observable, of } from 'rxjs'; - -import { Credentials, CredentialsService } from './credentials.service'; - -export interface LoginContext { - username: string; - password: string; - remember?: boolean; -} - -/** - * Provides a base for authentication workflow. - * The login/logout methods should be replaced with proper implementation. - */ -@Injectable({ - providedIn: 'root', -}) -export class AuthenticationService { - constructor(private credentialsService: CredentialsService) {} - - /** - * Authenticates the user. - * @param context The login parameters. - * @return The user credentials. - */ - login(context: LoginContext): Observable { - // Replace by proper authentication call - const data = { - username: context.username, - token: '123456', - }; - this.credentialsService.setCredentials(data, context.remember); - return of(data); - } - - /** - * Logs out the user and clear credentials. - * @return True if the user was logged out successfully. - */ - logout(): Observable { - // Customize credentials invalidation here - this.credentialsService.setCredentials(); - return of(true); - } -} diff --git a/frontend/src/app/auth/credentials.service.mock.ts b/frontend/src/app/auth/credentials.service.mock.ts deleted file mode 100644 index bcacfe16..00000000 --- a/frontend/src/app/auth/credentials.service.mock.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Credentials } from './credentials.service'; - -export class MockCredentialsService { - credentials: Credentials | null = { - username: 'test', - token: '123', - }; - - isAuthenticated(): boolean { - return !!this.credentials; - } - - setCredentials(credentials?: Credentials, _remember?: boolean) { - this.credentials = credentials || null; - } -} diff --git a/frontend/src/app/auth/credentials.service.spec.ts b/frontend/src/app/auth/credentials.service.spec.ts deleted file mode 100644 index 0f20c433..00000000 --- a/frontend/src/app/auth/credentials.service.spec.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { TestBed, inject } from '@angular/core/testing'; - -import { CredentialsService, Credentials } from './credentials.service'; - -const credentialsKey = 'credentials'; - -describe('CredentialsService', () => { - let credentialsService: CredentialsService; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [CredentialsService], - }); - - credentialsService = TestBed.inject(CredentialsService); - }); - - afterEach(() => { - // Cleanup - localStorage.removeItem(credentialsKey); - sessionStorage.removeItem(credentialsKey); - }); - - describe('setCredentials', () => { - it('should authenticate user if credentials are set', () => { - // Act - credentialsService.setCredentials({ username: 'me', token: '123' }); - - // Assert - expect(credentialsService.isAuthenticated()).toBe(true); - expect((credentialsService.credentials as Credentials).username).toBe('me'); - }); - - it('should clean authentication', () => { - // Act - credentialsService.setCredentials(); - - // Assert - expect(credentialsService.isAuthenticated()).toBe(false); - }); - - it('should persist credentials for the session', () => { - // Act - credentialsService.setCredentials({ username: 'me', token: '123' }); - - // Assert - expect(sessionStorage.getItem(credentialsKey)).not.toBeNull(); - expect(localStorage.getItem(credentialsKey)).toBeNull(); - }); - - it('should persist credentials across sessions', () => { - // Act - credentialsService.setCredentials({ username: 'me', token: '123' }, true); - - // Assert - expect(localStorage.getItem(credentialsKey)).not.toBeNull(); - expect(sessionStorage.getItem(credentialsKey)).toBeNull(); - }); - - it('should clear user authentication', () => { - // Act - credentialsService.setCredentials(); - - // Assert - expect(credentialsService.isAuthenticated()).toBe(false); - expect(credentialsService.credentials).toBeNull(); - expect(sessionStorage.getItem(credentialsKey)).toBeNull(); - expect(localStorage.getItem(credentialsKey)).toBeNull(); - }); - }); -}); diff --git a/frontend/src/app/auth/credentials.service.ts b/frontend/src/app/auth/credentials.service.ts deleted file mode 100644 index 48a4b31e..00000000 --- a/frontend/src/app/auth/credentials.service.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { Injectable } from '@angular/core'; -import { environment } from '@env/environment'; - -export interface Credentials { - // Customize received credentials here - username: string; - token: string; -} - -const credentialsKey = 'credentials'; - -/** - * Provides storage for authentication credentials. - * The Credentials interface should be replaced with proper implementation. - */ -@Injectable({ - providedIn: 'root', -}) -export class CredentialsService { - private _credentials: Credentials | null = null; - - constructor() { - const savedCredentials = sessionStorage.getItem(credentialsKey) || localStorage.getItem(credentialsKey); - if (savedCredentials) { - this._credentials = JSON.parse(savedCredentials); - } - } - - /** - * Checks is the user is authenticated. - * @return True if the user is authenticated. - */ - isAuthenticated(): boolean { - return !!this.credentials || environment.auth === 'gcloud_iap' || environment.auth === 'single_user'; - } - - /** - * Gets the user credentials. - * @return The user credentials or null if the user is not authenticated. - */ - get credentials(): Credentials | null { - return this._credentials; - } - - /** - * Sets the user credentials. - * The credentials may be persisted across sessions by setting the `remember` parameter to true. - * Otherwise, the credentials are only persisted for the current session. - * @param credentials The user credentials. - * @param remember True to remember credentials across sessions. - */ - setCredentials(credentials?: Credentials, remember?: boolean) { - this._credentials = credentials || null; - - if (credentials) { - const storage = remember ? localStorage : sessionStorage; - storage.setItem(credentialsKey, JSON.stringify(credentials)); - } else { - sessionStorage.removeItem(credentialsKey); - localStorage.removeItem(credentialsKey); - } - } -} diff --git a/frontend/src/app/auth/index.ts b/frontend/src/app/auth/index.ts deleted file mode 100644 index 21f4f894..00000000 --- a/frontend/src/app/auth/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './auth.module'; -export * from './authentication.service'; -export * from './credentials.service'; -export * from './authentication.guard'; diff --git a/frontend/src/app/auth/login.component.html b/frontend/src/app/auth/login.component.html deleted file mode 100644 index 9e6eb4ca..00000000 --- a/frontend/src/app/auth/login.component.html +++ /dev/null @@ -1,51 +0,0 @@ -
-
-

APP_NAME

-
-

v{{ version }}

- -
-
- -
diff --git a/frontend/src/app/auth/login.component.scss b/frontend/src/app/auth/login.component.scss deleted file mode 100644 index 4e3b9131..00000000 --- a/frontend/src/app/auth/login.component.scss +++ /dev/null @@ -1,28 +0,0 @@ -@import "src/theme/theme-variables"; - -:host { - display: flex; - flex: 1; - background-color: #f5f5f5; -} - -.inline-loader { - display: inline-block; -} - -.version { - margin: 0; -} - -.login-container, -.mat-form-field { - width: 100%; -} - -.login-fields > :not(:last-child) { - margin-bottom: 8px; -} - -.login-error { - color: mat-color($app-warn); -} diff --git a/frontend/src/app/auth/login.component.spec.ts b/frontend/src/app/auth/login.component.spec.ts deleted file mode 100644 index c5d831bb..00000000 --- a/frontend/src/app/auth/login.component.spec.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; -import { TranslateModule } from '@ngx-translate/core'; -import { RouterTestingModule } from '@angular/router/testing'; -import { ReactiveFormsModule } from '@angular/forms'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { FlexLayoutModule } from '@angular/flex-layout'; - -import { SharedModule } from '@shared'; -import { MaterialModule } from '@app/material.module'; -import { AuthenticationService, CredentialsService } from '@app/auth'; -import { MockAuthenticationService } from '@app/auth/authentication.service.mock'; -import { MockCredentialsService } from '@app/auth/credentials.service.mock'; -import { I18nModule } from '@app/i18n'; -import { LoginComponent } from './login.component'; - -describe('LoginComponent', () => { - let component: LoginComponent; - let fixture: ComponentFixture; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [ - BrowserAnimationsModule, - FlexLayoutModule, - MaterialModule, - SharedModule, - RouterTestingModule, - TranslateModule.forRoot(), - I18nModule, - ReactiveFormsModule, - ], - declarations: [LoginComponent], - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(LoginComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/frontend/src/app/auth/login.component.ts b/frontend/src/app/auth/login.component.ts deleted file mode 100644 index 2b8919ef..00000000 --- a/frontend/src/app/auth/login.component.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { Router, ActivatedRoute } from '@angular/router'; -import { FormGroup, FormBuilder, Validators } from '@angular/forms'; -import { finalize } from 'rxjs/operators'; - -import { environment } from '@env/environment'; -import { Logger, UntilDestroy, untilDestroyed } from '@shared'; -import { AuthenticationService } from './authentication.service'; - -const log = new Logger('Login'); - -@UntilDestroy() -@Component({ - selector: 'app-login', - templateUrl: './login.component.html', - styleUrls: ['./login.component.scss'], -}) -export class LoginComponent implements OnInit { - version: string | null = environment.version; - error: string | undefined; - loginForm!: FormGroup; - isLoading = false; - - constructor( - private router: Router, - private route: ActivatedRoute, - private formBuilder: FormBuilder, - private authenticationService: AuthenticationService - ) { - this.createForm(); - } - - ngOnInit() {} - - login() { - this.isLoading = true; - const login$ = this.authenticationService.login(this.loginForm.value); - login$ - .pipe( - finalize(() => { - this.loginForm.markAsPristine(); - this.isLoading = false; - }), - untilDestroyed(this) - ) - .subscribe( - (credentials) => { - log.debug(`${credentials.username} successfully logged in`); - this.router.navigate([this.route.snapshot.queryParams['redirect'] || '/'], { replaceUrl: true }); - }, - (error) => { - log.debug(`Login error: ${error}`); - this.error = error; - } - ); - } - - private createForm() { - this.loginForm = this.formBuilder.group({ - username: ['', Validators.required], - password: ['', Validators.required], - remember: true, - }); - } -} diff --git a/frontend/src/app/chat/chat-controls/chat-controls.component.html b/frontend/src/app/chat/chat-controls/chat-controls.component.html deleted file mode 100644 index 2f115bb1..00000000 --- a/frontend/src/app/chat/chat-controls/chat-controls.component.html +++ /dev/null @@ -1,66 +0,0 @@ - - -
- - - - - - - - {{ llm.name }} - - - - - - - - - -
- - - -
Attachments:
- - - insert_drive_file - {{ attachment.name }} - cancel - - -
-
-
diff --git a/frontend/src/app/chat/chat-controls/chat-controls.component.scss b/frontend/src/app/chat/chat-controls/chat-controls.component.scss deleted file mode 100644 index be68b840..00000000 --- a/frontend/src/app/chat/chat-controls/chat-controls.component.scss +++ /dev/null @@ -1,7 +0,0 @@ -:host { - position: sticky; - bottom: 0; - background-color: #fff; - padding: 1rem 0; - z-index: 1; -} diff --git a/frontend/src/app/chat/chat-controls/chat-controls.component.spec.ts b/frontend/src/app/chat/chat-controls/chat-controls.component.spec.ts deleted file mode 100644 index a2c9b02e..00000000 --- a/frontend/src/app/chat/chat-controls/chat-controls.component.spec.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { ReactiveFormsModule } from '@angular/forms'; -import { ChatControlsComponent } from './chat-controls.component'; -import { ApiChatService } from '@app/chat/services/api/api-chat.service'; -import { LlmService } from '@app/shared/services/llm.service'; -import { of } from 'rxjs'; -import { MaterialModule } from '@app/material.module'; - -describe.skip('ChatControlsComponent', () => { - let component: ChatControlsComponent; - let fixture: ComponentFixture; - let apiChatServiceSpy: jest.Mocked; - let llmServiceSpy: jest.Mocked; - - beforeEach(async () => { - apiChatServiceSpy = { - sendMessage: jest.fn(), - } as unknown as jest.Mocked; - llmServiceSpy = { - getLlms: jest.fn(), - } as unknown as jest.Mocked; - - await TestBed.configureTestingModule({ - declarations: [ChatControlsComponent], - imports: [ReactiveFormsModule, MaterialModule], - providers: [ - { provide: ApiChatService, useValue: apiChatServiceSpy }, - { provide: LlmService, useValue: llmServiceSpy }, - ], - }).compileComponents(); - - fixture = TestBed.createComponent(ChatControlsComponent); - component = fixture.componentInstance; - - // llmServiceSpy.getLlms.and.returnValue(of([{ id: 'llm1', name: 'LLM 1' }])); - - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should call submit method when form is valid and submit button is clicked', () => { - spyOn(component, 'submit'); - component.chatId = 'testChatId'; - component.chatForm.patchValue({ - message: 'Test message', - selectedLlm: 'llm1', - }); - fixture.detectChanges(); - - const submitButton = fixture.nativeElement.querySelector('button[color="primary"]'); - submitButton.click(); - - expect(component.submit).toHaveBeenCalled(); - }); - - it('should call submit method when all fields are filled and submit button is clicked', () => { - spyOn(component, 'submit'); - component.chatId = 'testChatId'; - component.chatForm.patchValue({ - message: 'Test message', - selectedLlm: 'llm1', - }); - fixture.detectChanges(); - - const submitButton = fixture.nativeElement.querySelector('button[color="primary"]'); - submitButton.click(); - - expect(component.submit).toHaveBeenCalled(); - expect(apiChatServiceSpy.sendMessage).toHaveBeenCalledWith('testChatId', 'Test message', 'llm1'); - }); - - it('should send message when submit method is called with valid form', () => { - component.chatId = 'testChatId'; - component.chatForm.patchValue({ - message: 'Test message', - selectedLlm: 'llm1', - }); - apiChatServiceSpy.sendMessage.mockReturnValue(of({ data: 'Response message' })); - - component.submit(); - - expect(apiChatServiceSpy.sendMessage).toHaveBeenCalledWith('testChatId', 'Test message', 'llm1'); - expect(component.isSending).toBeFalsy(); - }); - - it('should show alert when submit is called without chat ID', () => { - spyOn(window, 'alert'); - component.chatId = ''; - component.chatForm.patchValue({ - message: 'Test message', - selectedLlm: 'llm1', - }); - - component.submit(); - - expect(window.alert).toHaveBeenCalledWith('Unable to send message. Please try again later.'); - }); -}); diff --git a/frontend/src/app/chat/chat-controls/chat-controls.component.ts b/frontend/src/app/chat/chat-controls/chat-controls.component.ts deleted file mode 100644 index 612e98ff..00000000 --- a/frontend/src/app/chat/chat-controls/chat-controls.component.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { Component, Input, OnInit, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core'; -import { FormBuilder, FormGroup } from '@angular/forms'; -import { debounceTime, filter, throttleTime } from 'rxjs/operators'; -import { ApiChatService } from '@app/chat/services/api/api-chat.service'; -import { LlmService } from '@app/shared/services/llm.service'; -import { LlmMessage } from '@app/chat/model/chat'; -import { Data } from '@shared'; - -@Component({ - selector: 'app-chat-controls', - templateUrl: './chat-controls.component.html', - styleUrls: ['./chat-controls.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class ChatControlsComponent implements OnInit { - @Input() chatId: string = ''; - @Output() messageSent = new EventEmitter(); - @Output() chatError = new EventEmitter(); - - chatForm: FormGroup; - isSending: boolean = false; - llms: any[] = []; - - constructor(private chatService: ApiChatService, private llmService: LlmService, private fb: FormBuilder) { - this.chatForm = this.fb.group({ - message: [''], - selectedLlm: [''], - }); - } - - ngOnInit() { - this.scrollBottom(); - this.fetchLlms(); - - this.chatForm - .get('message') - ?.valueChanges.pipe( - filter((data: string) => data !== ''), - throttleTime(1400) - ) - .subscribe(() => { - // Implement typing indicator if needed - }); - - this.chatForm - .get('message') - ?.valueChanges.pipe( - filter((data: string) => data !== ''), - debounceTime(1500) - ) - .subscribe(() => { - // Implement typing indicator removal if needed - }); - } - - private fetchLlms(): void { - this.llmService.getLlms().subscribe({ - next: (llms) => { - this.llms = llms; - if (this.llms.length > 0) { - this.chatForm.get('selectedLlm')?.setValue(this.llms[0].id); - } - }, - error: (error) => { - console.error('Error fetching LLMs:', error); - // Consider showing a user-friendly error message here - }, - }); - } - - submit(): void { - console.log('Submit method called'); // Debug log - const msg = this.chatForm.get('message')?.value; - const selectedLlmId = this.chatForm.get('selectedLlm')?.value; - - if (!this.chatId) { - console.error('Chat ID is not set'); - this.chatError.emit('Unable to send message. Please try again later.'); - return; - } - - if (!msg) { - this.chatError.emit('Please enter a message.'); - return; - } - if (!selectedLlmId) { - this.chatError.emit('Please select an LLM.'); - return; - } - - this.isSending = true; - this.chatService.sendMessage(this.chatId, msg, selectedLlmId).subscribe({ - next: (data: Data) => { - console.log(data.data); - this.isSending = false; - this.chatForm.get('message')?.reset(); - this.scrollBottom(); - this.messageSent.emit([ - { role: 'user', text: msg, index: -1 }, - { role: 'assistant', text: data.data, index: -1, llmId: selectedLlmId }, - ]); - }, - error: (err: Error) => { - console.error('Error sending message:', err); - this.isSending = false; - this.chatError.emit('Failed to send message. Please try again.'); - }, - }); - } - - private scrollBottom(): void { - setTimeout(() => window.scrollTo(0, document.body.scrollHeight), 500); - } - - // Attachment methods left as placeholders for future implementation - setSelectedFiles(event: Event): void {} - deleteAttachment(file: File): void {} - getAttachments(): File[] { - return []; - } - hasAttachments(): boolean { - return false; - } -} diff --git a/frontend/src/app/chat/chat-header/chat-header.component.html b/frontend/src/app/chat/chat-header/chat-header.component.html deleted file mode 100644 index 39b193da..00000000 --- a/frontend/src/app/chat/chat-header/chat-header.component.html +++ /dev/null @@ -1,7 +0,0 @@ - - Chat - {{ chatId }} - - - diff --git a/frontend/src/app/chat/chat-header/chat-header.component.scss b/frontend/src/app/chat/chat-header/chat-header.component.scss deleted file mode 100644 index e69de29b..00000000 diff --git a/frontend/src/app/chat/chat-header/chat-header.component.spec.ts b/frontend/src/app/chat/chat-header/chat-header.component.spec.ts deleted file mode 100644 index 51a9e53f..00000000 --- a/frontend/src/app/chat/chat-header/chat-header.component.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { ChatHeaderComponent } from './chat-header.component'; - -describe('ChatHeaderComponent', () => { - let component: ChatHeaderComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ChatHeaderComponent], - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(ChatHeaderComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/frontend/src/app/chat/chat-header/chat-header.component.ts b/frontend/src/app/chat/chat-header/chat-header.component.ts deleted file mode 100644 index e8398c78..00000000 --- a/frontend/src/app/chat/chat-header/chat-header.component.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Component, Input } from '@angular/core'; - -@Component({ - selector: 'app-chat-header', - templateUrl: './chat-header.component.html', - styleUrls: ['./chat-header.component.scss'], -}) -export class ChatHeaderComponent { - @Input() chatId: string = ''; -} diff --git a/frontend/src/app/chat/chat-list/chat-list.component.html b/frontend/src/app/chat/chat-list/chat-list.component.html deleted file mode 100644 index 155fe327..00000000 --- a/frontend/src/app/chat/chat-list/chat-list.component.html +++ /dev/null @@ -1,30 +0,0 @@ - - - Chats - - - - - - - -
- -
-
{{ chat.title }}
-
-
-

No chats. Start one by clicking the plus icon above.

-
- - -

{{ errorMessage }}

-
-
diff --git a/frontend/src/app/chat/chat-list/chat-list.component.scss b/frontend/src/app/chat/chat-list/chat-list.component.scss deleted file mode 100644 index 587a3b51..00000000 --- a/frontend/src/app/chat/chat-list/chat-list.component.scss +++ /dev/null @@ -1,9 +0,0 @@ -/* Styles for CodeReviewListComponent */ -[matListItemIcon] { - display: flex; - gap: 4px; /* Reduce the gap between buttons */ -} - -button[mat-icon-button] { - padding: 0; /* Remove default padding */ -} diff --git a/frontend/src/app/chat/chat-list/chat-list.component.ts b/frontend/src/app/chat/chat-list/chat-list.component.ts deleted file mode 100644 index 3ad50766..00000000 --- a/frontend/src/app/chat/chat-list/chat-list.component.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { MatDialog } from '@angular/material/dialog'; -import { Router } from '@angular/router'; - -import { MatDialogModule } from '@angular/material/dialog'; -import { ApiChatService } from '@app/chat/services/api/api-chat.service'; -import { ChatList } from '@app/chat/model/chat'; - -@Component({ - selector: 'app-code-chat-list', - templateUrl: './chat-list.component.html', - styleUrls: ['./chat-list.component.scss'], -}) -export class ChatListComponent implements OnInit { - chats: ChatList | null = null; - isLoading = false; - errorMessage = ''; - - constructor(private chatService: ApiChatService, private router: Router, private dialog: MatDialog) {} - - ngOnInit() { - this.loadChats(); - } - - loadChats() { - this.isLoading = true; - this.chatService.list().subscribe( - (chats) => { - console.log(chats); - this.chats = chats.data; - this.isLoading = false; - }, - (error: any) => { - console.log(error); - this.errorMessage = 'Error loading configurations'; - this.isLoading = false; - } - ); - } - - openChat(chatId?: string) { - this.router.navigate(['/chat', chatId]).catch(console.error); - } - - // confirmDelete(config: CodeReviewConfig) { - // const dialogRef = this.dialog.open(ConfirmDialogComponent, { - // width: '400px', - // data: { title: 'Confirm Deletion', message: `Are you sure you want to delete "${config.description}"?` }, - // }); - // - // dialogRef.afterClosed().subscribe((result) => { - // if (result) { - // this.deleteConfig(config.id); - // } - // }); - // } - // - // private deleteConfig(id: string) { - // this.codeReviewService.deleteCodeReviewConfig(id).subscribe( - // () => this.loadConfigs(), - // (error) => { - // this.errorMessage = 'Error deleting configuration'; - // } - // ); - // } -} diff --git a/frontend/src/app/chat/chat-message/chat-message.component.html b/frontend/src/app/chat/chat-message/chat-message.component.html deleted file mode 100644 index 8e8d8495..00000000 --- a/frontend/src/app/chat/chat-message/chat-message.component.html +++ /dev/null @@ -1,60 +0,0 @@ -
- - - - - - - - - - - - - - - - - -
diff --git a/frontend/src/app/chat/chat-message/chat-message.component.scss b/frontend/src/app/chat/chat-message/chat-message.component.scss deleted file mode 100644 index 7b6527b9..00000000 --- a/frontend/src/app/chat/chat-message/chat-message.component.scss +++ /dev/null @@ -1,29 +0,0 @@ -.message-bubble { - /* Common styles for all message bubbles */ - border-radius: 8px; - padding: 8px 12px; - max-width: 70%; - word-wrap: break-word; -} - -.user-message { - /* Styles specific to user messages */ - margin-left: auto; - margin-right: 10%; -} - -.assistant-message { - /* Styles specific to assistant messages */ - margin-right: auto; - margin-left: 10%; -} - -/* Responsive design for smaller screens */ -@media (max-width: 600px) { - .user-message, - .assistant-message { - max-width: 85%; - margin-left: 5%; - margin-right: 5%; - } -} diff --git a/frontend/src/app/chat/chat-message/chat-message.component.spec.ts b/frontend/src/app/chat/chat-message/chat-message.component.spec.ts deleted file mode 100644 index 8c018a69..00000000 --- a/frontend/src/app/chat/chat-message/chat-message.component.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { ChatMessageComponent } from './chat-message.component'; - -describe('ChatMessageComponent', () => { - let component: ChatMessageComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - // TestBed.configureTestingModule({ - // declarations: [ChatMessageComponent], - // }).compileComponents(); - })); - - beforeEach(() => { - // fixture = TestBed.createComponent(ChatMessageComponent); - // component = fixture.componentInstance; - // fixture.detectChanges(); - }); - - it('should create', () => { - // expect(component).toBeTruthy(); - }); -}); diff --git a/frontend/src/app/chat/chat-message/chat-message.component.ts b/frontend/src/app/chat/chat-message/chat-message.component.ts deleted file mode 100644 index 2cd368c6..00000000 --- a/frontend/src/app/chat/chat-message/chat-message.component.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { LlmMessage, User } from '@app/chat/model/chat'; -import { MarkdownService } from 'ngx-markdown'; - -@Component({ - selector: 'app-chat-message', - templateUrl: './chat-message.component.html', - styleUrls: ['./chat-message.component.scss'], -}) -export class ChatMessageComponent implements OnInit { - @Input() msg: LlmMessage = {} as LlmMessage; - @Input() predecessor: LlmMessage | null = null; - @Input() allowsReply = false; - - constructor(private markdown: MarkdownService) {} - - ngOnInit() {} - - getDateDivider(msg: LlmMessage | undefined): string { - if (!msg || !msg.createdAt) { - return ''; - } - return new Date(msg.createdAt).toLocaleDateString(); - } - - getUserName(role: 'system' | 'user' | 'assistant'): string { - switch (role) { - case 'user': - return 'You'; - case 'assistant': - return 'Assistant'; - case 'system': - return 'System'; - default: - return 'Unknown'; - } - } - - getCreatedDate(msg: LlmMessage): string | null { - if (!msg.createdAt) { - return null; - } - return new Date(msg.createdAt).toLocaleTimeString(); - } - - isPredecessorSameAuthor(): boolean { - if (!this.predecessor) { - return false; - } - return this.predecessor.role === this.msg.role; - } - - isTemporalClose(): boolean { - if (!this.predecessor || !this.msg.createdAt || !this.predecessor.createdAt) { - return false; - } - const timeDiff = Math.abs(this.msg.createdAt - this.predecessor.createdAt); - return timeDiff <= 60000; // 1 minute in milliseconds - } - - isPreviousMessageFromOtherDay() { - if (!this.predecessor || !this.msg.createdAt || !this.predecessor.createdAt) { - return true; - } - const prevDate = new Date(this.predecessor.createdAt).toDateString(); - const currentDate = new Date(this.msg.createdAt).toDateString(); - return prevDate !== currentDate; - } -} diff --git a/frontend/src/app/chat/chat-routing.module.ts b/frontend/src/app/chat/chat-routing.module.ts deleted file mode 100644 index 8cd3ce7e..00000000 --- a/frontend/src/app/chat/chat-routing.module.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { NgModule } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; - -import { ChatComponent } from './chat/chat.component'; -import { ChatListComponent } from '@app/chat/chat-list/chat-list.component'; -import { marker } from '@biesbjerg/ngx-translate-extract-marker'; - -const routes: Routes = [ - { - path: '', - component: ChatListComponent, - data: { title: marker('Chat') }, - }, - { - path: ':id', - component: ChatComponent, - }, -]; - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule], - providers: [], -}) -export class ChatRoutingModule {} diff --git a/frontend/src/app/chat/chat.module.ts b/frontend/src/app/chat/chat.module.ts deleted file mode 100644 index d51896a5..00000000 --- a/frontend/src/app/chat/chat.module.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { TranslateModule } from '@ngx-translate/core'; -import { FlexLayoutModule } from '@angular/flex-layout'; - -import { MaterialModule } from '@app/material.module'; -import { ChatRoutingModule } from '@app/chat/chat-routing.module'; -import { ChatComponent } from './chat/chat.component'; -import { ChatControlsComponent } from './chat-controls/chat-controls.component'; -import { ChatMessageComponent } from './chat-message/chat-message.component'; -import { ChatHeaderComponent } from './chat-header/chat-header.component'; -import { ChatListComponent } from '@app/chat/chat-list/chat-list.component'; -import { MarkdownModule } from 'ngx-markdown'; - -@NgModule({ - imports: [ - CommonModule, - TranslateModule, - FlexLayoutModule, - MaterialModule, - ChatRoutingModule, - MarkdownModule.forChild(), - ], - declarations: [ChatComponent, ChatControlsComponent, ChatMessageComponent, ChatHeaderComponent, ChatListComponent], -}) -export class ChatModule {} diff --git a/frontend/src/app/chat/chat/chat.component.html b/frontend/src/app/chat/chat/chat.component.html deleted file mode 100644 index af02e4d5..00000000 --- a/frontend/src/app/chat/chat/chat.component.html +++ /dev/null @@ -1,8 +0,0 @@ -
-
- - - -
- -
diff --git a/frontend/src/app/chat/chat/chat.component.scss b/frontend/src/app/chat/chat/chat.component.scss deleted file mode 100644 index b17cfc7c..00000000 --- a/frontend/src/app/chat/chat/chat.component.scss +++ /dev/null @@ -1,21 +0,0 @@ -.chat-container { - display: flex; - flex-direction: column; - height: 93vh; - width: 95%; - // max-width: 900px; -} - -.messages-container { - flex: 1; - overflow-y: auto; - padding: 1rem; - max-height: calc(93vh - 100px); // Adjust the value as needed -} - -app-chat-controls { - position: sticky; - bottom: 0; - background-color: #fff; - padding: 1rem 0; -} diff --git a/frontend/src/app/chat/chat/chat.component.ts b/frontend/src/app/chat/chat/chat.component.ts deleted file mode 100644 index aa52f55e..00000000 --- a/frontend/src/app/chat/chat/chat.component.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { Component, OnInit, Input, ViewChild, ElementRef, OnDestroy } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { BehaviorSubject, Subject } from 'rxjs'; -import { map, takeUntil, debounceTime } from 'rxjs/operators'; -import { Chat, LlmMessage } from '@app/chat/model/chat'; -import { ApiChatService } from '@app/chat/services/api/api-chat.service'; - -@Component({ - selector: 'app-chat', - templateUrl: './chat.component.html', - styleUrls: ['./chat.component.scss'], -}) -export class ChatComponent implements OnInit, OnDestroy { - @Input() height: string = ''; - @Input() width: string = ''; - @ViewChild('messagesContainer') private messagesContainer!: ElementRef; - - chat$: BehaviorSubject = new BehaviorSubject({ - id: 'new', - updatedAt: 0, - messages: [], - title: '', - userId: '', - parentId: undefined, - visibility: 'private', - }); - - private shouldScrollToBottom = true; - private destroy$ = new Subject(); - private scrollEvent$ = new Subject(); - - constructor(private route: ActivatedRoute, private chatService: ApiChatService) {} - - ngOnInit() { - const chatId: string | null = this.route.snapshot.paramMap.get('id'); - if (!chatId || chatId === 'new') { - setTimeout(() => this.scrollToBottom(), 0); - } else { - this.chatService - .getChat(chatId) - .pipe( - map((data: any) => data.data), - takeUntil(this.destroy$) - ) - .subscribe({ - next: (chat: Chat) => { - this.chat$.next(chat); - setTimeout(() => this.scrollToBottom(), 0); - }, - error: (error) => { - console.error('Error loading chat:', error); - // Handle error (e.g., show error message to user) - }, - }); - } - - this.scrollEvent$.pipe(debounceTime(200), takeUntil(this.destroy$)).subscribe(() => this.checkScrollPosition()); - } - - ngOnDestroy() { - this.destroy$.next(); - this.destroy$.complete(); - } - - trackByCreated(index: number, msg: LlmMessage) { - return msg.index; - } - - onMessageSent(messages: LlmMessage[]) { - const currentChat = this.chat$.value; - messages[0].index = currentChat.messages.length; - messages[1].index = currentChat.messages.length + 1; - currentChat.messages.push(messages[0], messages[1]); - this.chat$.next(currentChat); - this.shouldScrollToBottom = true; - setTimeout(() => this.scrollToBottom(), 0); - } - - private scrollToBottom() { - if (this.messagesContainer) { - const element = this.messagesContainer.nativeElement; - element.scrollTop = element.scrollHeight; - } - } - - onScroll() { - this.scrollEvent$.next(); - } - - private checkScrollPosition() { - if (this.messagesContainer) { - const element = this.messagesContainer.nativeElement; - const atBottom = element.scrollHeight - element.scrollTop === element.clientHeight; - this.shouldScrollToBottom = atBottom; - } - } -} diff --git a/frontend/src/app/chat/model/chat.ts b/frontend/src/app/chat/model/chat.ts deleted file mode 100644 index 6ad475d8..00000000 --- a/frontend/src/app/chat/model/chat.ts +++ /dev/null @@ -1,31 +0,0 @@ -export interface LlmMessage { - role: 'system' | 'user' | 'assistant'; - text: string; - llmId?: string; - /** Set the cache_control flag with Claude models */ - cache?: 'ephemeral'; - index: number; - createdAt?: number; -} - -export interface User { - displayName: string; -} - -export interface Chat { - id: string; - userId: string; - visibility: 'private' | 'public'; - title: string; - updatedAt: number; - /** When a chat is branched from the original thread by deleting/updating messages etc */ - parentId: undefined | string; - messages: LlmMessage[]; -} - -export type ChatPreview = Omit; - -export interface ChatList { - chats: ChatPreview[]; - hasMore: boolean; -} diff --git a/frontend/src/app/chat/model/message.ts b/frontend/src/app/chat/model/message.ts deleted file mode 100644 index 9ee5c15e..00000000 --- a/frontend/src/app/chat/model/message.ts +++ /dev/null @@ -1,13 +0,0 @@ -// import { User } from './user'; - -// export interface Attachment { -// name: string; -// } -// -// export interface Message { -// content: string; -// uid: string; -// createdAt: number; -// user: User; -// attachments: Attachment[]; -// } diff --git a/frontend/src/app/chat/services/api/api-chat.service.spec.ts b/frontend/src/app/chat/services/api/api-chat.service.spec.ts deleted file mode 100644 index fcbce637..00000000 --- a/frontend/src/app/chat/services/api/api-chat.service.spec.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { ApiChatService } from './api-chat.service'; - -describe('ApiChatService', () => { - beforeEach(() => { - // TestBed.configureTestingModule({}) - }); - - it('should be created', () => { - // const service: ApiChatService = TestBed.get(ApiChatService); - // expect(service).to.not.be.undefined; - }); -}); diff --git a/frontend/src/app/chat/services/api/api-chat.service.ts b/frontend/src/app/chat/services/api/api-chat.service.ts deleted file mode 100644 index 0202bae4..00000000 --- a/frontend/src/app/chat/services/api/api-chat.service.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Chat, ChatList } from '../../model/chat'; -import { Observable } from 'rxjs'; -import { Data } from '@shared'; -import { HttpClient } from '@angular/common/http'; - -// Service client for the chat routes - -@Injectable({ - providedIn: 'root', -}) -export class ApiChatService { - // extends ChatBaseService - constructor(private http: HttpClient) { - // super(); - } - - async create(): Promise { - return false; - } - - // async deleteMessage(chat: Chat, msg: Message): Promise { - // return undefined; - // } - - list(startAfterId?: string): Observable> { - return this.http.get>(`/chats`); // { params: {startAfterId} } - } - - getChat(chatId: string): Observable> { - return this.http.get>(`/chat/${chatId}`); - } - - sendMessage(chatId: string, content: string, llmId: string): Observable> { - return this.http.post>(`/chat/${chatId}/send`, { text: content, llmId }); - } -} diff --git a/frontend/src/app/chat/services/chat-base.service.ts b/frontend/src/app/chat/services/chat-base.service.ts deleted file mode 100644 index 9d82a15c..00000000 --- a/frontend/src/app/chat/services/chat-base.service.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Chat } from '../model/chat'; -import { Observable } from 'rxjs'; -import { ServicesConfig } from './services-config'; -import { Injectable, Optional } from '@angular/core'; - -export abstract class ChatBaseService { - constructor(@Optional() config?: ServicesConfig) { - if (config) { - console.log('Config:', config); - } - } - - abstract getChat(chatId: string): Observable; - - // abstract create(): Promise; - // - // abstract sendMessage(chatId: string, content: string): Promise; - // - // abstract deleteMessage(chat: Chat, msg: Message): Promise; - // - // abstract sendIsTyping(chatId: string): Promise; - // - // abstract deleteIsTyping(chatId: string): Promise; - // - // abstract buildChat(source: Observable) ; -} diff --git a/frontend/src/app/chat/services/services-config.ts b/frontend/src/app/chat/services/services-config.ts deleted file mode 100644 index f8278087..00000000 --- a/frontend/src/app/chat/services/services-config.ts +++ /dev/null @@ -1,12 +0,0 @@ -export class ServicesConfig { - firebase: - | { - chat: string; - } - | undefined; - apiEndpoints: - | { - history: string; - } - | undefined; -} diff --git a/frontend/src/app/chat/services/services.module.ts b/frontend/src/app/chat/services/services.module.ts deleted file mode 100644 index 2ca4af19..00000000 --- a/frontend/src/app/chat/services/services.module.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { ChatBaseService } from './chat-base.service'; -import { ServicesConfig } from './services-config'; - -/** - * Help: https://angular.io/guide/singleton-services - */ - -@NgModule({ - declarations: [], - imports: [CommonModule], -}) -export class ServicesModule { - constructor(@Optional() @SkipSelf() parentModule?: ServicesModule) { - if (parentModule) { - throw new Error('GreetingModule is already loaded. Import it in the AppModule only'); - } - } - - static forRoot(config: ServicesConfig): ModuleWithProviders { - return { - ngModule: ServicesModule, - providers: [{ provide: ServicesConfig, useValue: config }], - }; - } -} diff --git a/frontend/src/app/code-review/code-review-edit.component.html b/frontend/src/app/code-review/code-review-edit.component.html deleted file mode 100644 index 1dd1aa49..00000000 --- a/frontend/src/app/code-review/code-review-edit.component.html +++ /dev/null @@ -1,139 +0,0 @@ - - - {{ configId ? 'Edit' : 'Create' }} Code Review Configuration - - -
-
- - Description - - -
-
- -
-
-
- - Included File Extensions - - - {{ ext }} - cancel - - - - -
- -
- - Required Text In Diff - - - {{ text }} - cancel - - - - -
-
-
-
- -
-
-
- - Tags - - - {{ tag }} - cancel - - - - -
- -
- - Project Paths - - - {{ path }} - cancel - - - - -
-
-
-
- -
-
-

- Examples - -

-
-
-
- - Code - - - - Review Comment - - -
- -
-
- - - - - -
-
-
diff --git a/frontend/src/app/code-review/code-review-edit.component.scss b/frontend/src/app/code-review/code-review-edit.component.scss deleted file mode 100644 index f262bcf5..00000000 --- a/frontend/src/app/code-review/code-review-edit.component.scss +++ /dev/null @@ -1,84 +0,0 @@ -/* Styles for CodeReviewEditComponent */ - -.full-width { - width: 100%; -} - -.row { - display: flex; - flex-wrap: wrap; - margin: -10px; -} - -.col { - flex: 1; - padding: 10px; - min-width: 200px; -} - -.examples-section { - width: 100%; - margin-top: 20px; -} - -.examples-header { - margin-bottom: 10px; - - h3 { - display: flex; - align-items: center; - margin: 0; - - button { - margin-left: 8px; - } - } -} - -.example-row { - display: flex; - align-items: flex-start; - margin-bottom: 20px; -} - -.example-fields { - display: flex; - width: 100%; -} - -.code-field, -.review-comment-field { - width: 50%; - padding-right: 10px; -} - -.remove-example-button { - align-self: flex-start; - margin-top: 10px; -} - -textarea { - min-height: 100px; -} -.form-row { - display: flex; - align-items: flex-start; - margin-bottom: 16px; - margin-right: 10px; -} - -.full-width { - flex-grow: 1; -} - -.spacer { - width: 40px; /* Adjust this value to match the width of your delete icon button */ -} - -.row { - display: flex; -} - -.col { - flex: 1; -} diff --git a/frontend/src/app/code-review/code-review-edit.component.spec.ts b/frontend/src/app/code-review/code-review-edit.component.spec.ts deleted file mode 100644 index 2d9e50c2..00000000 --- a/frontend/src/app/code-review/code-review-edit.component.spec.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { ReactiveFormsModule } from '@angular/forms'; -import { RouterTestingModule } from '@angular/router/testing'; -import { MatChipsModule, MatChipInputEvent, MatChipInput } from '@angular/material/chips'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatInputModule } from '@angular/material/input'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { CodeReviewEditComponent } from './code-review-edit.component'; -import { CodeReviewService } from './code-review.service'; - -describe('CodeReviewEditComponent', () => { - let component: CodeReviewEditComponent; - let fixture: ComponentFixture; - let mockCodeReviewService: jest.Mocked; - - beforeEach(async () => { - mockCodeReviewService = { - getCodeReviewConfig: jest.fn(), - updateCodeReviewConfig: jest.fn(), - createCodeReviewConfig: jest.fn(), - } as unknown as jest.Mocked; - - await TestBed.configureTestingModule({ - declarations: [CodeReviewEditComponent], - imports: [ - ReactiveFormsModule, - RouterTestingModule, - MatChipsModule, - MatFormFieldModule, - MatInputModule, - NoopAnimationsModule, - ], - providers: [{ provide: CodeReviewService, useValue: mockCodeReviewService }], - }).compileComponents(); - - fixture = TestBed.createComponent(CodeReviewEditComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should initialize the form with empty values', () => { - expect(component.editForm.get('description')?.value).toBe(''); - expect(component.editForm.get('file_extensions.include')?.value).toEqual([]); - expect(component.editForm.get('requires.text')?.value).toEqual([]); - expect(component.editForm.get('examples')?.value).toEqual([]); - }); - - it('should validate required fields', () => { - const form = component.editForm; - expect(form.valid).toBeFalsy(); - - form.patchValue({ - description: 'Test description', - file_extensions: { include: ['js'] }, - requires: { text: ['TODO'] }, - }); - component.addExample(); - const exampleGroup = (component.editForm.get('examples') as any).controls[0]; - exampleGroup.patchValue({ - code: 'console.log("Hello");', - review_comment: 'Use proper logging', - }); - - expect(form.valid).toBeTruthy(); - }); - - it('should validate arrayNotEmpty for file extensions', () => { - const fileExtensions = component.editForm.get('file_extensions.include'); - expect(fileExtensions?.valid).toBeFalsy(); - - fileExtensions?.setValue(['js']); - expect(fileExtensions?.valid).toBeTruthy(); - - fileExtensions?.setValue([]); - expect(fileExtensions?.valid).toBeFalsy(); - }); - - it('should validate arrayNotEmpty for required text', () => { - const requiredText = component.editForm.get('requires.text'); - expect(requiredText?.valid).toBeFalsy(); - - requiredText?.setValue(['TODO']); - expect(requiredText?.valid).toBeTruthy(); - - requiredText?.setValue([]); - expect(requiredText?.valid).toBeFalsy(); - }); - - it('should validate arrayNotEmpty for examples', () => { - const examples = component.editForm.get('examples'); - expect(examples?.valid).toBeFalsy(); - - component.addExample(); - const exampleGroup = (component.editForm.get('examples') as any).controls[0]; - exampleGroup.patchValue({ - code: 'console.log("Hello");', - review_comment: 'Use proper logging', - }); - expect(examples?.valid).toBeTruthy(); - - component.removeExample(0); - expect(examples?.valid).toBeFalsy(); - }); - - it('should add and remove file extensions', () => { - const fileExtensions = component.editForm.get('file_extensions.include'); - const mockInput = document.createElement('input'); - const mockEvent: MatChipInputEvent = { - value: 'js', - input: mockInput, - chipInput: { clear: jest.fn() } as unknown as MatChipInput, - }; - component.addExtension(mockEvent); - expect(fileExtensions?.value).toEqual(['js']); - - component.removeExtension('js'); - expect(fileExtensions?.value).toEqual([]); - }); - - it('should add and remove required text', () => { - const requiredText = component.editForm.get('requires.text'); - const mockInput = document.createElement('input'); - const mockEvent: MatChipInputEvent = { - value: 'TODO', - input: mockInput, - chipInput: { clear: jest.fn() } as unknown as MatChipInput, - }; - component.addRequiredText(mockEvent); - expect(requiredText?.value).toEqual(['TODO']); - - component.removeRequiredText('TODO'); - expect(requiredText?.value).toEqual([]); - }); - - it('should initialize the form correctly', () => { - expect(component.editForm.get('file_extensions.include')?.value).toEqual([]); - expect(component.editForm.get('requires.text')?.value).toEqual([]); - }); - - it('should add and remove examples', () => { - component.addExample(); - expect(component.examples.length).toBe(1); - - component.removeExample(0); - expect(component.examples.length).toBe(0); - }); -}); diff --git a/frontend/src/app/code-review/code-review-list.component.html b/frontend/src/app/code-review/code-review-list.component.html deleted file mode 100644 index 50f92ea2..00000000 --- a/frontend/src/app/code-review/code-review-list.component.html +++ /dev/null @@ -1,31 +0,0 @@ - - - Code Review Configurations - - - - - - -
- - -
-
{{ config.description }}
-
-
-

No code reviews configured

-
- - -

{{ errorMessage }}

-
-
diff --git a/frontend/src/app/code-review/code-review-list.component.scss b/frontend/src/app/code-review/code-review-list.component.scss deleted file mode 100644 index 587a3b51..00000000 --- a/frontend/src/app/code-review/code-review-list.component.scss +++ /dev/null @@ -1,9 +0,0 @@ -/* Styles for CodeReviewListComponent */ -[matListItemIcon] { - display: flex; - gap: 4px; /* Reduce the gap between buttons */ -} - -button[mat-icon-button] { - padding: 0; /* Remove default padding */ -} diff --git a/frontend/src/app/code-review/code-review-list.component.ts b/frontend/src/app/code-review/code-review-list.component.ts deleted file mode 100644 index 421d1b9c..00000000 --- a/frontend/src/app/code-review/code-review-list.component.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { MatDialog } from '@angular/material/dialog'; -import { Router } from '@angular/router'; -import { CodeReviewService } from './code-review.service'; -import { CodeReviewConfig } from './code-review.model'; -import { ConfirmDialogComponent } from '../shared/confirm-dialog/confirm-dialog.component'; -import { MatDialogModule } from '@angular/material/dialog'; - -@Component({ - selector: 'app-code-review-list', - templateUrl: './code-review-list.component.html', - styleUrls: ['./code-review-list.component.scss'], -}) -export class CodeReviewListComponent implements OnInit { - configs: CodeReviewConfig[] | null = null; - isLoading = false; - errorMessage = ''; - - constructor(private codeReviewService: CodeReviewService, private router: Router, private dialog: MatDialog) {} - - ngOnInit() { - this.loadConfigs(); - } - - loadConfigs() { - this.isLoading = true; - this.codeReviewService.getCodeReviewConfigs().subscribe( - (configs) => { - console.log(configs); - this.configs = configs.data; - this.isLoading = false; - }, - (error) => { - this.errorMessage = 'Error loading configurations'; - this.isLoading = false; - } - ); - } - - openEditPage(id?: string) { - if (id) { - this.router.navigate(['/code-reviews/edit', id]).catch(console.error); - } else { - this.router.navigate(['/code-reviews/new']).catch(console.error); - } - } - - confirmDelete(config: CodeReviewConfig) { - const dialogRef = this.dialog.open(ConfirmDialogComponent, { - width: '400px', - data: { title: 'Confirm Deletion', message: `Are you sure you want to delete "${config.description}"?` }, - }); - - dialogRef.afterClosed().subscribe((result) => { - if (result) { - this.deleteConfig(config.id); - } - }); - } - - private deleteConfig(id: string) { - this.codeReviewService.deleteCodeReviewConfig(id).subscribe( - () => this.loadConfigs(), - (error) => { - this.errorMessage = 'Error deleting configuration'; - } - ); - } -} diff --git a/frontend/src/app/code-review/code-review-routing.module.ts b/frontend/src/app/code-review/code-review-routing.module.ts deleted file mode 100644 index 56efe431..00000000 --- a/frontend/src/app/code-review/code-review-routing.module.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { NgModule } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; - -import { CodeReviewEditComponent } from './code-review-edit.component'; -import { CodeReviewListComponent } from './code-review-list.component'; -import { marker } from '@biesbjerg/ngx-translate-extract-marker'; - -const routes: Routes = [ - { - path: '', - component: CodeReviewListComponent, - data: { title: marker('Code Reviews') }, - }, - { - path: 'new', - component: CodeReviewEditComponent, - }, - { - path: 'edit/:id', - component: CodeReviewEditComponent, - }, -]; - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule], - providers: [], -}) -export class CodeReviewRoutingModule {} diff --git a/frontend/src/app/code-review/code-review.module.ts b/frontend/src/app/code-review/code-review.module.ts deleted file mode 100644 index 4552f896..00000000 --- a/frontend/src/app/code-review/code-review.module.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { TranslateModule } from '@ngx-translate/core'; -import { FlexLayoutModule } from '@angular/flex-layout'; - -import { MaterialModule } from '@app/material.module'; -import { CodeReviewRoutingModule } from '@app/code-review/code-review-routing.module'; -import { CodeReviewListComponent } from '@app/code-review/code-review-list.component'; -import { CodeReviewEditComponent } from '@app/code-review/code-review-edit.component'; -import { MatSnackBarModule } from '@angular/material/snack-bar'; - -@NgModule({ - imports: [ - CommonModule, - TranslateModule, - MatSnackBarModule, - FlexLayoutModule, - MaterialModule, - CodeReviewRoutingModule, - ], - declarations: [CodeReviewListComponent, CodeReviewEditComponent], -}) -export class CodeReviewModule {} diff --git a/frontend/src/app/code/code.component.spec.ts b/frontend/src/app/code/code.component.spec.ts deleted file mode 100644 index 2567a09c..00000000 --- a/frontend/src/app/code/code.component.spec.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { ReactiveFormsModule } from '@angular/forms'; -import { MaterialModule } from '@app/material.module'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { CodeComponent } from './code.component'; -import { CodeService } from '@app/shared/services/code.service'; -import { of, throwError } from 'rxjs'; - -describe.skip('CodeComponent', () => { - let component: CodeComponent; - let fixture: ComponentFixture; - let codeService: jest.Mocked; - - beforeEach(async () => { - const codeServiceMock = { - runCodebaseQuery: jest.fn(), - getRepositories: jest.fn(), - runCodeEditWorkflow: jest.fn(), - selectFilesToEdit: jest.fn(), - }; - - await TestBed.configureTestingModule({ - declarations: [CodeComponent], - imports: [ReactiveFormsModule, MaterialModule, NoopAnimationsModule], - providers: [{ provide: CodeService, useValue: codeServiceMock }], - }).compileComponents(); - - codeService = TestBed.inject(CodeService) as jest.Mocked; - }); - - beforeEach(() => { - fixture = TestBed.createComponent(CodeComponent); - component = fixture.componentInstance; - codeService.getRepositories.mockReturnValue(of(['repo1', 'repo2'])); - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should execute codebase query operation and update result', () => { - component.codeForm.setValue({ - workingDirectory: 'repo1', - operationType: 'query', - input: 'test query', - }); - - codeService.runCodebaseQuery.mockReturnValue(of({ response: 'Query result' })); - - component.onSubmit(); - - expect(codeService.runCodebaseQuery).toHaveBeenCalledWith('repo1', 'test query'); - expect(component.result).toBe('Query result'); - expect(component.isLoading).toBeFalsy(); - }); - - it('should execute code edit workflow operation and update result', () => { - component.codeForm.setValue({ - workingDirectory: 'repo1', - operationType: 'code', - input: 'edit requirements', - }); - - const mockResponse = { changes: ['file1.ts', 'file2.ts'] }; - codeService.runCodeEditWorkflow.mockReturnValue(of(mockResponse)); - - component.onSubmit(); - - expect(codeService.runCodeEditWorkflow).toHaveBeenCalledWith('repo1', 'edit requirements'); - expect(component.result).toBe(JSON.stringify(mockResponse, null, 2)); - expect(component.isLoading).toBeFalsy(); - }); - - it('should execute select files operation and update result', () => { - component.codeForm.setValue({ - workingDirectory: 'repo1', - operationType: 'selectFiles', - input: 'selection criteria', - }); - - const mockResponse = { selectedFiles: ['file1.ts', 'file2.ts'] }; - codeService.selectFilesToEdit.mockReturnValue(of(mockResponse)); - - component.onSubmit(); - - expect(codeService.selectFilesToEdit).toHaveBeenCalledWith('repo1', 'selection criteria'); - expect(component.result).toBe(JSON.stringify(mockResponse, null, 2)); - expect(component.isLoading).toBeFalsy(); - }); - - it('should handle errors during operation execution', () => { - component.codeForm.setValue({ - workingDirectory: 'repo1', - operationType: 'query', - input: 'test query', - }); - - const errorMessage = 'API Error'; - codeService.runCodebaseQuery.mockReturnValue(throwError(() => new Error(errorMessage))); - - component.onSubmit(); - - expect(codeService.runCodebaseQuery).toHaveBeenCalledWith('repo1', 'test query'); - expect(component.result).toBe(`Error during query operation: ${errorMessage}`); - expect(component.isLoading).toBeFalsy(); - }); - - it('should handle invalid operation type', () => { - component.codeForm.setValue({ - workingDirectory: 'repo1', - operationType: 'invalidType', - input: 'test input', - }); - - component.onSubmit(); - - expect(component.result).toBe('Error: Invalid operation type'); - expect(component.isLoading).toBeFalsy(); - }); -}); diff --git a/frontend/src/app/code/code.module.ts b/frontend/src/app/code/code.module.ts deleted file mode 100644 index 125f6c45..00000000 --- a/frontend/src/app/code/code.module.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { ReactiveFormsModule } from '@angular/forms'; -import { RouterModule } from '@angular/router'; -import { CodeComponent } from './code.component'; -import { MaterialModule } from '@app/material.module'; -import { marker } from '@biesbjerg/ngx-translate-extract-marker'; - -@NgModule({ - imports: [ - CommonModule, - ReactiveFormsModule, - MaterialModule, - RouterModule.forChild([{ path: '', component: CodeComponent, data: { title: marker('Repository actions') } }]), - ], - declarations: [CodeComponent], -}) -export class CodeModule {} diff --git a/frontend/src/app/core/auth/auth.interceptor.ts b/frontend/src/app/core/auth/auth.interceptor.ts new file mode 100644 index 00000000..edfd77a7 --- /dev/null +++ b/frontend/src/app/core/auth/auth.interceptor.ts @@ -0,0 +1,62 @@ +import { + HttpErrorResponse, + HttpEvent, + HttpHandlerFn, + HttpRequest, +} from '@angular/common/http'; +import { inject } from '@angular/core'; +import { AuthService } from 'app/core/auth/auth.service'; +import { AuthUtils } from 'app/core/auth/auth.utils'; +import { Observable, catchError, throwError } from 'rxjs'; + +/** + * Intercept + * + * @param req + * @param next + */ +export const authInterceptor = ( + req: HttpRequest, + next: HttpHandlerFn +): Observable> => { + const authService = inject(AuthService); + + // Clone the request object + let newReq = req.clone(); + + // Request + // + // If the access token didn't expire, add the Authorization header. + // We won't add the Authorization header if the access token expired. + // This will force the server to return a "401 Unauthorized" response + // for the protected API routes which our response interceptor will + // catch and delete the access token from the local storage while logging + // the user out from the app. + if ( + authService.accessToken && + !AuthUtils.isTokenExpired(authService.accessToken) + ) { + newReq = req.clone({ + headers: req.headers.set( + 'Authorization', + 'Bearer ' + authService.accessToken + ), + }); + } + + // Response + return next(newReq).pipe( + catchError((error) => { + // Catch "401 Unauthorized" responses + if (error instanceof HttpErrorResponse && error.status === 401) { + // Sign out + authService.signOut(); + + // Reload the app + location.reload(); + } + + return throwError(error); + }) + ); +}; diff --git a/frontend/src/app/core/auth/auth.provider.ts b/frontend/src/app/core/auth/auth.provider.ts new file mode 100644 index 00000000..81beefe3 --- /dev/null +++ b/frontend/src/app/core/auth/auth.provider.ts @@ -0,0 +1,20 @@ +import { provideHttpClient, withInterceptors } from '@angular/common/http'; +import { + ENVIRONMENT_INITIALIZER, + EnvironmentProviders, + Provider, + inject, +} from '@angular/core'; +import { authInterceptor } from 'app/core/auth/auth.interceptor'; +import { AuthService } from 'app/core/auth/auth.service'; + +export const provideAuth = (): Array => { + return [ + provideHttpClient(withInterceptors([authInterceptor])), + { + provide: ENVIRONMENT_INITIALIZER, + useValue: () => inject(AuthService), + multi: true, + }, + ]; +}; diff --git a/frontend/src/app/core/auth/auth.service.ts b/frontend/src/app/core/auth/auth.service.ts new file mode 100644 index 00000000..08c86b27 --- /dev/null +++ b/frontend/src/app/core/auth/auth.service.ts @@ -0,0 +1,178 @@ +import { HttpClient } from '@angular/common/http'; +import { inject, Injectable } from '@angular/core'; +import { AuthUtils } from 'app/core/auth/auth.utils'; +import { UserService } from 'app/core/user/user.service'; +import { catchError, Observable, of, switchMap, throwError } from 'rxjs'; + +@Injectable({ providedIn: 'root' }) +export class AuthService { + private _authenticated: boolean = false; + private _httpClient = inject(HttpClient); + private _userService = inject(UserService); + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Setter & getter for access token + */ + set accessToken(token: string) { + localStorage.setItem('accessToken', token); + } + + get accessToken(): string { + return localStorage.getItem('accessToken') ?? ''; + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Forgot password + * + * @param email + */ + forgotPassword(email: string): Observable { + return this._httpClient.post('api/auth/forgot-password', email); + } + + /** + * Reset password + * + * @param password + */ + resetPassword(password: string): Observable { + return this._httpClient.post('api/auth/reset-password', password); + } + + /** + * Sign in + * + * @param credentials + */ + signIn(credentials: { email: string; password: string }): Observable { + // Throw error, if the user is already logged in + if (this._authenticated) { + return throwError('User is already logged in.'); + } + + return this._httpClient.post('api/auth/sign-in', credentials).pipe( + switchMap((response: any) => { + // Store the access token in the local storage + this.accessToken = response.accessToken; + + // Set the authenticated flag to true + this._authenticated = true; + + // Store the user on the user service + this._userService.user = response.user; + + // Return a new observable with the response + return of(response); + }) + ); + } + + /** + * Sign in using the access token + */ + signInUsingToken(): Observable { + // Sign in using the token + return this._httpClient + .post('api/auth/sign-in-with-token', { + accessToken: this.accessToken, + }) + .pipe( + catchError(() => + // Return false + of(false) + ), + switchMap((response: any) => { + // Replace the access token with the new one if it's available on + // the response object. + // + // This is an added optional step for better security. Once you sign + // in using the token, you should generate a new one on the server + // side and attach it to the response object. Then the following + // piece of code can replace the token with the refreshed one. + if (response.accessToken) { + this.accessToken = response.accessToken; + } + + // Set the authenticated flag to true + this._authenticated = true; + + // Store the user on the user service + this._userService.user = response.user; + + // Return true + return of(true); + }) + ); + } + + /** + * Sign out + */ + signOut(): Observable { + // Remove the access token from the local storage + localStorage.removeItem('accessToken'); + + // Set the authenticated flag to false + this._authenticated = false; + + // Return the observable + return of(true); + } + + /** + * Sign up + * + * @param user + */ + signUp(user: { + name: string; + email: string; + password: string; + company: string; + }): Observable { + return this._httpClient.post('api/auth/sign-up', user); + } + + /** + * Unlock session + * + * @param credentials + */ + unlockSession(credentials: { + email: string; + password: string; + }): Observable { + return this._httpClient.post('api/auth/unlock-session', credentials); + } + + /** + * Check the authentication status + */ + check(): Observable { + // Check if the user is logged in + if (this._authenticated) { + return of(true); + } + + // Check the access token availability + if (!this.accessToken) { + return of(false); + } + + // Check the access token expire date + if (AuthUtils.isTokenExpired(this.accessToken)) { + return of(false); + } + + // If the access token exists, and it didn't expire, sign in using it + return this.signInUsingToken(); + } +} diff --git a/frontend/src/app/core/auth/auth.utils.ts b/frontend/src/app/core/auth/auth.utils.ts new file mode 100644 index 00000000..e5a7e3ec --- /dev/null +++ b/frontend/src/app/core/auth/auth.utils.ts @@ -0,0 +1,182 @@ +// ----------------------------------------------------------------------------------------------------- +// @ AUTH UTILITIES +// +// Methods are derivations of the Auth0 Angular-JWT helper service methods +// https://github.com/auth0/angular2-jwt +// ----------------------------------------------------------------------------------------------------- + +export class AuthUtils { + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Is token expired? + * + * @param token + * @param offsetSeconds + */ + static isTokenExpired(token: string, offsetSeconds?: number): boolean { + // Return if there is no token + if (!token || token === '') { + return true; + } + + // Get the expiration date + const date = this._getTokenExpirationDate(token); + + offsetSeconds = offsetSeconds || 0; + + if (date === null) { + return true; + } + + // Check if the token is expired + return !(date.valueOf() > new Date().valueOf() + offsetSeconds * 1000); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Private methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Base64 decoder + * Credits: https://github.com/atk + * + * @param str + * @private + */ + private static _b64decode(str: string): string { + const chars = + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + let output = ''; + + str = String(str).replace(/=+$/, ''); + + if (str.length % 4 === 1) { + throw new Error( + "'atob' failed: The string to be decoded is not correctly encoded." + ); + } + + /* eslint-disable */ + for ( + // initialize result and counters + let bc = 0, bs: any, buffer: any, idx = 0; + // get next character + (buffer = str.charAt(idx++)); + // character found in table? initialize bit storage and add its ascii value; + ~buffer && + ((bs = bc % 4 ? bs * 64 + buffer : buffer), + // and if not first of each 4 characters, + // convert the first 8 bits to one ascii character + bc++ % 4) + ? (output += String.fromCharCode(255 & (bs >> ((-2 * bc) & 6)))) + : 0 + ) { + // try to find character in table (0-63, not found => -1) + buffer = chars.indexOf(buffer); + } + /* eslint-enable */ + + return output; + } + + /** + * Base64 unicode decoder + * + * @param str + * @private + */ + private static _b64DecodeUnicode(str: any): string { + return decodeURIComponent( + Array.prototype.map + .call( + this._b64decode(str), + (c: any) => + '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2) + ) + .join('') + ); + } + + /** + * URL Base 64 decoder + * + * @param str + * @private + */ + private static _urlBase64Decode(str: string): string { + let output = str.replace(/-/g, '+').replace(/_/g, '/'); + switch (output.length % 4) { + case 0: { + break; + } + case 2: { + output += '=='; + break; + } + case 3: { + output += '='; + break; + } + default: { + throw Error('Illegal base64url string!'); + } + } + return this._b64DecodeUnicode(output); + } + + /** + * Decode token + * + * @param token + * @private + */ + private static _decodeToken(token: string): any { + // Return if there is no token + if (!token) { + return null; + } + + // Split the token + const parts = token.split('.'); + + if (parts.length !== 3) { + throw new Error( + "The inspected token doesn't appear to be a JWT. Check to make sure it has three parts and see https://jwt.io for more." + ); + } + + // Decode the token using the Base64 decoder + const decoded = this._urlBase64Decode(parts[1]); + + if (!decoded) { + throw new Error('Cannot decode the token.'); + } + + return JSON.parse(decoded); + } + + /** + * Get token expiration date + * + * @param token + * @private + */ + private static _getTokenExpirationDate(token: string): Date | null { + // Get the decoded token + const decodedToken = this._decodeToken(token); + + // Return if the decodedToken doesn't have an 'exp' field + if (!decodedToken.hasOwnProperty('exp')) { + return null; + } + + // Convert the expiration date + const date = new Date(0); + date.setUTCSeconds(decodedToken.exp); + + return date; + } +} diff --git a/frontend/src/app/core/auth/guards/auth.guard.ts b/frontend/src/app/core/auth/guards/auth.guard.ts new file mode 100644 index 00000000..e98780cb --- /dev/null +++ b/frontend/src/app/core/auth/guards/auth.guard.ts @@ -0,0 +1,30 @@ +import { inject } from '@angular/core'; +import { CanActivateChildFn, CanActivateFn, Router } from '@angular/router'; +import { AuthService } from 'app/core/auth/auth.service'; +import { of, switchMap } from 'rxjs'; + +export const AuthGuard: CanActivateFn | CanActivateChildFn = (route, state) => { + const router: Router = inject(Router); + + // Check the authentication status + return inject(AuthService) + .check() + .pipe( + switchMap((authenticated) => { + // If the user is not authenticated... + if (!authenticated) { + // Redirect to the sign-in page with a redirectUrl param + const redirectURL = + state.url === '/sign-out' + ? '' + : `redirectURL=${state.url}`; + const urlTree = router.parseUrl(`sign-in?${redirectURL}`); + + return of(urlTree); + } + + // Allow the access + return of(true); + }) + ); +}; diff --git a/frontend/src/app/core/auth/guards/noAuth.guard.ts b/frontend/src/app/core/auth/guards/noAuth.guard.ts new file mode 100644 index 00000000..99b6af01 --- /dev/null +++ b/frontend/src/app/core/auth/guards/noAuth.guard.ts @@ -0,0 +1,26 @@ +import { inject } from '@angular/core'; +import { CanActivateChildFn, CanActivateFn, Router } from '@angular/router'; +import { AuthService } from 'app/core/auth/auth.service'; +import { of, switchMap } from 'rxjs'; + +export const NoAuthGuard: CanActivateFn | CanActivateChildFn = ( + route, + state +) => { + const router: Router = inject(Router); + + // Check the authentication status + return inject(AuthService) + .check() + .pipe( + switchMap((authenticated) => { + // If the user is authenticated... + if (authenticated) { + return of(router.parseUrl('')); + } + + // Allow the access + return of(true); + }) + ); +}; diff --git a/frontend/src/app/core/icons/icons.provider.ts b/frontend/src/app/core/icons/icons.provider.ts new file mode 100644 index 00000000..12f34ec1 --- /dev/null +++ b/frontend/src/app/core/icons/icons.provider.ts @@ -0,0 +1,17 @@ +import { + ENVIRONMENT_INITIALIZER, + EnvironmentProviders, + inject, + Provider, +} from '@angular/core'; +import { IconsService } from 'app/core/icons/icons.service'; + +export const provideIcons = (): Array => { + return [ + { + provide: ENVIRONMENT_INITIALIZER, + useValue: () => inject(IconsService), + multi: true, + }, + ]; +}; diff --git a/frontend/src/app/core/icons/icons.service.ts b/frontend/src/app/core/icons/icons.service.ts new file mode 100644 index 00000000..8f9b1660 --- /dev/null +++ b/frontend/src/app/core/icons/icons.service.ts @@ -0,0 +1,55 @@ +import { inject, Injectable } from '@angular/core'; +import { MatIconRegistry } from '@angular/material/icon'; +import { DomSanitizer } from '@angular/platform-browser'; + +@Injectable({ providedIn: 'root' }) +export class IconsService { + /** + * Constructor + */ + constructor() { + const domSanitizer = inject(DomSanitizer); + const matIconRegistry = inject(MatIconRegistry); + + // Register icon sets + matIconRegistry.addSvgIconSet( + domSanitizer.bypassSecurityTrustResourceUrl( + 'icons/material-twotone.svg' + ) + ); + matIconRegistry.addSvgIconSetInNamespace( + 'mat_outline', + domSanitizer.bypassSecurityTrustResourceUrl( + 'icons/material-outline.svg' + ) + ); + matIconRegistry.addSvgIconSetInNamespace( + 'mat_solid', + domSanitizer.bypassSecurityTrustResourceUrl( + 'icons/material-solid.svg' + ) + ); + matIconRegistry.addSvgIconSetInNamespace( + 'feather', + domSanitizer.bypassSecurityTrustResourceUrl('icons/feather.svg') + ); + matIconRegistry.addSvgIconSetInNamespace( + 'heroicons_outline', + domSanitizer.bypassSecurityTrustResourceUrl( + 'icons/heroicons-outline.svg' + ) + ); + matIconRegistry.addSvgIconSetInNamespace( + 'heroicons_solid', + domSanitizer.bypassSecurityTrustResourceUrl( + 'icons/heroicons-solid.svg' + ) + ); + matIconRegistry.addSvgIconSetInNamespace( + 'heroicons_mini', + domSanitizer.bypassSecurityTrustResourceUrl( + 'icons/heroicons-mini.svg' + ) + ); + } +} diff --git a/frontend/src/app/core/interceptors/base-url.interceptor.ts b/frontend/src/app/core/interceptors/base-url.interceptor.ts new file mode 100644 index 00000000..0c1afe00 --- /dev/null +++ b/frontend/src/app/core/interceptors/base-url.interceptor.ts @@ -0,0 +1,20 @@ +import { Injectable } from '@angular/core'; +import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { environment } from '../../../environments/environment'; + +@Injectable() +export class BaseUrlInterceptor implements HttpInterceptor { + intercept(request: HttpRequest, next: HttpHandler): Observable> { + // console.log(`BaseUrlInterceptor ${request.url}`); + let url = request.url.startsWith('api/') && !request.url.startsWith('api/common/') && !request.url.startsWith('api/apps/') && !request.url.startsWith('api/auth/') ? + `${environment.apiBaseUrl}${request.url.substring(4)}` : + request.url; + if(url.startsWith('/api/')) + url = `${environment.apiBaseUrl}${request.url.substring(5)}` + + const apiRequest = request.clone({ url }); + // console.log(`apiRequest ${apiRequest.url}`) + return next.handle(apiRequest); + } +} diff --git a/frontend/src/app/core/navigation/navigation.service.ts b/frontend/src/app/core/navigation/navigation.service.ts new file mode 100644 index 00000000..ba31cde2 --- /dev/null +++ b/frontend/src/app/core/navigation/navigation.service.ts @@ -0,0 +1,37 @@ +import { HttpClient } from '@angular/common/http'; +import { inject, Injectable } from '@angular/core'; +import { Navigation } from 'app/core/navigation/navigation.types'; +import { Observable, ReplaySubject, tap } from 'rxjs'; + +@Injectable({ providedIn: 'root' }) +export class NavigationService { + private _httpClient = inject(HttpClient); + private _navigation: ReplaySubject = + new ReplaySubject(1); + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Getter for navigation + */ + get navigation$(): Observable { + return this._navigation.asObservable(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Get all navigation data + */ + get(): Observable { + return this._httpClient.get('api/common/navigation').pipe( + tap((navigation) => { + this._navigation.next(navigation); + }) + ); + } +} diff --git a/frontend/src/app/core/navigation/navigation.types.ts b/frontend/src/app/core/navigation/navigation.types.ts new file mode 100644 index 00000000..65f8fb61 --- /dev/null +++ b/frontend/src/app/core/navigation/navigation.types.ts @@ -0,0 +1,8 @@ +import { FuseNavigationItem } from '@fuse/components/navigation'; + +export interface Navigation { + compact: FuseNavigationItem[]; + default: FuseNavigationItem[]; + futuristic: FuseNavigationItem[]; + horizontal: FuseNavigationItem[]; +} diff --git a/frontend/src/app/core/transloco/transloco.http-loader.ts b/frontend/src/app/core/transloco/transloco.http-loader.ts new file mode 100644 index 00000000..a583b0c2 --- /dev/null +++ b/frontend/src/app/core/transloco/transloco.http-loader.ts @@ -0,0 +1,22 @@ +import { HttpClient } from '@angular/common/http'; +import { inject, Injectable } from '@angular/core'; +import { Translation, TranslocoLoader } from '@ngneat/transloco'; +import { Observable } from 'rxjs'; + +@Injectable({ providedIn: 'root' }) +export class TranslocoHttpLoader implements TranslocoLoader { + private _httpClient = inject(HttpClient); + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Get translation + * + * @param lang + */ + getTranslation(lang: string): Observable { + return this._httpClient.get(`./i18n/${lang}.json`); + } +} diff --git a/frontend/src/app/core/user/user.service.ts b/frontend/src/app/core/user/user.service.ts new file mode 100644 index 00000000..90c1bd2e --- /dev/null +++ b/frontend/src/app/core/user/user.service.ts @@ -0,0 +1,56 @@ +import { HttpClient } from '@angular/common/http'; +import { inject, Injectable } from '@angular/core'; +import { User } from 'app/core/user/user.types'; +import { map, Observable, ReplaySubject, tap } from 'rxjs'; + +@Injectable({ providedIn: 'root' }) +export class UserService { + private _httpClient = inject(HttpClient); + private _user: ReplaySubject = new ReplaySubject(1); + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Setter & getter for user + * + * @param value + */ + set user(value: User) { + // Store the value + this._user.next(value); + } + + get user$(): Observable { + return this._user.asObservable(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Get the current signed-in user data + */ + get(): Observable { + return this._httpClient.get('api/common/user').pipe( + tap((user) => { + this._user.next(user); + }) + ); + } + + /** + * Update the user + * + * @param user + */ + update(user: User): Observable { + return this._httpClient.patch('api/common/user', { user }).pipe( + map((response) => { + this._user.next(response); + }) + ); + } +} diff --git a/frontend/src/app/core/user/user.types.ts b/frontend/src/app/core/user/user.types.ts new file mode 100644 index 00000000..01e5d60c --- /dev/null +++ b/frontend/src/app/core/user/user.types.ts @@ -0,0 +1,7 @@ +export interface User { + id: string; + name: string; + email: string; + avatar?: string; + status?: string; +} diff --git a/frontend/src/app/home/home-routing.module.ts b/frontend/src/app/home/home-routing.module.ts deleted file mode 100644 index 40924717..00000000 --- a/frontend/src/app/home/home-routing.module.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { NgModule } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; -import { marker } from '@biesbjerg/ngx-translate-extract-marker'; - -import { HomeComponent } from './home.component'; -import { Shell } from '@app/shell/shell.service'; - -const routes: Routes = [ - Shell.childRoutes([ - { path: '', redirectTo: '/agents', pathMatch: 'full' }, - { path: 'home', component: HomeComponent, data: { title: marker('Home') } }, - ]), -]; - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule], - providers: [], -}) -export class HomeRoutingModule {} diff --git a/frontend/src/app/home/home.component.html b/frontend/src/app/home/home.component.html deleted file mode 100644 index 5e12fcf1..00000000 --- a/frontend/src/app/home/home.component.html +++ /dev/null @@ -1,14 +0,0 @@ -
- -

- -

- - Hello world ! - - - {{ quote }} - - -
-
diff --git a/frontend/src/app/home/home.component.scss b/frontend/src/app/home/home.component.scss deleted file mode 100644 index 0c9b2fa7..00000000 --- a/frontend/src/app/home/home.component.scss +++ /dev/null @@ -1,14 +0,0 @@ -.container { - text-align: center; - padding: 1em; -} - -.logo { - width: 150px; - margin: 0 auto; -} - -q { - font-style: italic; - quotes: "« " " »"; -} diff --git a/frontend/src/app/home/home.component.spec.ts b/frontend/src/app/home/home.component.spec.ts deleted file mode 100644 index 2a2812b5..00000000 --- a/frontend/src/app/home/home.component.spec.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { FlexLayoutModule } from '@angular/flex-layout'; - -import { SharedModule } from '@shared'; -import { MaterialModule } from '@app/material.module'; -import { HomeComponent } from './home.component'; -import { QuoteService } from './quote.service'; - -describe('HomeComponent', () => { - let component: HomeComponent; - let fixture: ComponentFixture; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [BrowserAnimationsModule, FlexLayoutModule, MaterialModule, SharedModule, HttpClientTestingModule], - declarations: [HomeComponent], - providers: [QuoteService], - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(HomeComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/frontend/src/app/home/home.component.ts b/frontend/src/app/home/home.component.ts deleted file mode 100644 index 911e43bf..00000000 --- a/frontend/src/app/home/home.component.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { finalize } from 'rxjs/operators'; - -import { QuoteService } from './quote.service'; - -@Component({ - selector: 'app-home', - templateUrl: './home.component.html', - styleUrls: ['./home.component.scss'], -}) -export class HomeComponent implements OnInit { - quote: string | undefined; - isLoading = false; - - constructor(private quoteService: QuoteService) {} - - ngOnInit() { - this.isLoading = true; - this.quoteService - .getRandomQuote({ category: 'dev' }) - .pipe( - finalize(() => { - this.isLoading = false; - }) - ) - .subscribe((quote: string) => { - this.quote = quote; - }); - } -} diff --git a/frontend/src/app/home/home.module.ts b/frontend/src/app/home/home.module.ts deleted file mode 100644 index aeb22984..00000000 --- a/frontend/src/app/home/home.module.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { TranslateModule } from '@ngx-translate/core'; -import { FlexLayoutModule } from '@angular/flex-layout'; - -import { SharedModule } from '@shared'; -import { MaterialModule } from '@app/material.module'; -import { HomeRoutingModule } from './home-routing.module'; -import { HomeComponent } from './home.component'; - -@NgModule({ - imports: [CommonModule, TranslateModule, SharedModule, FlexLayoutModule, MaterialModule, HomeRoutingModule], - declarations: [HomeComponent], -}) -export class HomeModule {} diff --git a/frontend/src/app/home/quote.service.spec.ts b/frontend/src/app/home/quote.service.spec.ts deleted file mode 100644 index b40f5387..00000000 --- a/frontend/src/app/home/quote.service.spec.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Type } from '@angular/core'; -import { TestBed } from '@angular/core/testing'; -import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; - -import { QuoteService } from './quote.service'; - -describe('QuoteService', () => { - let quoteService: QuoteService; - let httpMock: HttpTestingController; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [QuoteService], - }); - - quoteService = TestBed.inject(QuoteService); - httpMock = TestBed.inject(HttpTestingController as Type); - }); - - afterEach(() => { - httpMock.verify(); - }); - - describe('getRandomQuote', () => { - it('should return a random Chuck Norris quote', () => { - // Arrange - const mockQuote = { value: 'a random quote' }; - - // Act - const randomQuoteSubscription = quoteService.getRandomQuote({ category: 'toto' }); - - // Assert - randomQuoteSubscription.subscribe((quote: string) => { - expect(quote).toEqual(mockQuote.value); - }); - httpMock.expectOne({}).flush(mockQuote); - }); - - it('should return a string in case of error', () => { - // Act - const randomQuoteSubscription = quoteService.getRandomQuote({ category: 'toto' }); - - // Assert - randomQuoteSubscription.subscribe((quote: string) => { - expect(typeof quote).toEqual('string'); - expect(quote).toContain('Error'); - }); - httpMock.expectOne({}).flush(null, { - status: 500, - statusText: 'error', - }); - }); - }); -}); diff --git a/frontend/src/app/home/quote.service.ts b/frontend/src/app/home/quote.service.ts deleted file mode 100644 index 32a23e15..00000000 --- a/frontend/src/app/home/quote.service.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { Observable, of } from 'rxjs'; -import { map, catchError } from 'rxjs/operators'; - -const routes = { - quote: (c: RandomQuoteContext) => `/jokes/random?category=${c.category}`, -}; - -export interface RandomQuoteContext { - // The quote's category: 'dev', 'explicit'... - category: string; -} - -@Injectable({ - providedIn: 'root', -}) -export class QuoteService { - constructor(private httpClient: HttpClient) {} - - getRandomQuote(context: RandomQuoteContext): Observable { - return this.httpClient.get(routes.quote(context)).pipe( - map((body: any) => body.value), - catchError(() => of('Error, could not load joke :-(')) - ); - } -} diff --git a/frontend/src/app/i18n/i18n.module.ts b/frontend/src/app/i18n/i18n.module.ts deleted file mode 100644 index 6bd07bed..00000000 --- a/frontend/src/app/i18n/i18n.module.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { TranslateModule } from '@ngx-translate/core'; -import { FlexLayoutModule } from '@angular/flex-layout'; - -import { MaterialModule } from '@app/material.module'; -import { LanguageSelectorComponent } from './language-selector.component'; - -@NgModule({ - imports: [CommonModule, TranslateModule, FlexLayoutModule, MaterialModule], - declarations: [LanguageSelectorComponent], - exports: [LanguageSelectorComponent], -}) -export class I18nModule {} diff --git a/frontend/src/app/i18n/i18n.service.spec.ts b/frontend/src/app/i18n/i18n.service.spec.ts deleted file mode 100644 index 09bade8d..00000000 --- a/frontend/src/app/i18n/i18n.service.spec.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { TranslateService, LangChangeEvent } from '@ngx-translate/core'; -import { Subject } from 'rxjs'; - -import { I18nService } from './i18n.service'; - -const defaultLanguage = 'en-US'; -const supportedLanguages = ['eo', 'en-US', 'fr-FR']; - -class MockTranslateService { - currentLang = ''; - onLangChange = new Subject(); - - use(language: string) { - this.currentLang = language; - this.onLangChange.next({ - lang: this.currentLang, - translations: {}, - }); - } - - getBrowserCultureLang() { - return 'en-US'; - } - - setTranslation(lang: string, translations: object, shouldMerge?: boolean) {} -} - -describe('I18nService', () => { - let i18nService: I18nService; - let translateService: TranslateService; - let onLangChangeSpy: jest.Mock; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [I18nService, { provide: TranslateService, useClass: MockTranslateService }], - }); - - i18nService = TestBed.inject(I18nService); - translateService = TestBed.inject(TranslateService); - - // Create spies - onLangChangeSpy = jest.fn(); - translateService.onLangChange.subscribe((event: LangChangeEvent) => { - onLangChangeSpy(event.lang); - }); - jest.spyOn(translateService, 'use'); - }); - - afterEach(() => { - // Cleanup - localStorage.removeItem('language'); - }); - - describe('init', () => { - it('should init with default language', () => { - // Act - i18nService.init(defaultLanguage, supportedLanguages); - - // Assert - expect(translateService.use).toHaveBeenCalledWith(defaultLanguage); - expect(onLangChangeSpy).toHaveBeenCalledWith(defaultLanguage); - }); - - it('should init with save language', () => { - // Arrange - const savedLanguage = 'eo'; - localStorage.setItem('language', savedLanguage); - - // Act - i18nService.init(defaultLanguage, supportedLanguages); - - // Assert - expect(translateService.use).toHaveBeenCalledWith(savedLanguage); - expect(onLangChangeSpy).toHaveBeenCalledWith(savedLanguage); - }); - }); - - describe('set language', () => { - it('should change current language', () => { - // Arrange - const newLanguage = 'eo'; - i18nService.init(defaultLanguage, supportedLanguages); - - // Act - i18nService.language = newLanguage; - - // Assert - expect(translateService.use).toHaveBeenCalledWith(newLanguage); - expect(onLangChangeSpy).toHaveBeenCalledWith(newLanguage); - }); - - it('should change current language without a region match', () => { - // Arrange - const newLanguage = 'fr-CA'; - i18nService.init(defaultLanguage, supportedLanguages); - - // Act - i18nService.language = newLanguage; - - // Assert - expect(translateService.use).toHaveBeenCalledWith('fr-FR'); - expect(onLangChangeSpy).toHaveBeenCalledWith('fr-FR'); - }); - - it('should change current language to default if unsupported', () => { - // Arrange - const newLanguage = 'es'; - i18nService.init(defaultLanguage, supportedLanguages); - - // Act - i18nService.language = newLanguage; - - // Assert - expect(translateService.use).toHaveBeenCalledWith(defaultLanguage); - expect(onLangChangeSpy).toHaveBeenCalledWith(defaultLanguage); - }); - }); - - describe('get language', () => { - it('should return current language', () => { - // Arrange - i18nService.init(defaultLanguage, supportedLanguages); - - // Act - const currentLanguage = i18nService.language; - - // Assert - expect(currentLanguage).toEqual(defaultLanguage); - }); - }); -}); diff --git a/frontend/src/app/i18n/i18n.service.ts b/frontend/src/app/i18n/i18n.service.ts deleted file mode 100644 index d8859fbe..00000000 --- a/frontend/src/app/i18n/i18n.service.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { Injectable } from '@angular/core'; -import { TranslateService, LangChangeEvent } from '@ngx-translate/core'; -import { Subscription } from 'rxjs'; - -import { Logger } from '@shared'; -import enUS from '../../translations/en-US.json'; - -const log = new Logger('I18nService'); -const languageKey = 'language'; - -@Injectable({ - providedIn: 'root', -}) -export class I18nService { - defaultLanguage!: string; - supportedLanguages!: string[]; - - private langChangeSubscription!: Subscription; - - constructor(private translateService: TranslateService) { - // Embed languages to avoid extra HTTP requests - translateService.setTranslation('en-US', enUS); - } - - /** - * Initializes i18n for the application. - * Loads language from local storage if present, or sets default language. - * @param defaultLanguage The default language to use. - * @param supportedLanguages The list of supported languages. - */ - init(defaultLanguage: string, supportedLanguages: string[]) { - this.defaultLanguage = defaultLanguage; - this.supportedLanguages = supportedLanguages; - this.language = ''; - - // Warning: this subscription will always be alive for the app's lifetime - this.langChangeSubscription = this.translateService.onLangChange.subscribe((event: LangChangeEvent) => { - localStorage.setItem(languageKey, event.lang); - }); - } - - /** - * Cleans up language change subscription. - */ - destroy() { - if (this.langChangeSubscription) { - this.langChangeSubscription.unsubscribe(); - } - } - - /** - * Sets the current language. - * Note: The current language is saved to the local storage. - * If no parameter is specified, the language is loaded from local storage (if present). - * @param language The IETF language code to set. - */ - set language(language: string) { - let newLanguage = - language || localStorage.getItem(languageKey) || this.translateService.getBrowserCultureLang() || ''; - let isSupportedLanguage = this.supportedLanguages.includes(newLanguage); - - // If no exact match is found, search without the region - if (newLanguage && !isSupportedLanguage) { - newLanguage = newLanguage.split('-')[0]; - newLanguage = - this.supportedLanguages.find((supportedLanguage) => supportedLanguage.startsWith(newLanguage)) || ''; - isSupportedLanguage = Boolean(newLanguage); - } - - // Fallback if language is not supported - if (!newLanguage || !isSupportedLanguage) { - newLanguage = this.defaultLanguage; - } - - language = newLanguage; - - log.debug(`Language set to ${language}`); - this.translateService.use(language); - } - - /** - * Gets the current language. - * @return The current language code. - */ - get language(): string { - return this.translateService.currentLang; - } -} diff --git a/frontend/src/app/i18n/index.ts b/frontend/src/app/i18n/index.ts deleted file mode 100644 index 088bb0b1..00000000 --- a/frontend/src/app/i18n/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './i18n.module'; -export * from './i18n.service'; -export * from './language-selector.component'; diff --git a/frontend/src/app/i18n/language-selector.component.html b/frontend/src/app/i18n/language-selector.component.html deleted file mode 100644 index 2326d246..00000000 --- a/frontend/src/app/i18n/language-selector.component.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - diff --git a/frontend/src/app/i18n/language-selector.component.scss b/frontend/src/app/i18n/language-selector.component.scss deleted file mode 100644 index e69de29b..00000000 diff --git a/frontend/src/app/i18n/language-selector.component.spec.ts b/frontend/src/app/i18n/language-selector.component.spec.ts deleted file mode 100644 index b5d96ba1..00000000 --- a/frontend/src/app/i18n/language-selector.component.spec.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; -import { TranslateModule } from '@ngx-translate/core'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { FlexLayoutModule } from '@angular/flex-layout'; - -import { MaterialModule } from '@app/material.module'; -import { I18nService } from './i18n.service'; -import { LanguageSelectorComponent } from './language-selector.component'; - -describe('LanguageSelectorComponent', () => { - let component: LanguageSelectorComponent; - let fixture: ComponentFixture; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [BrowserAnimationsModule, FlexLayoutModule, MaterialModule, TranslateModule.forRoot()], - declarations: [LanguageSelectorComponent], - providers: [I18nService], - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(LanguageSelectorComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/frontend/src/app/i18n/language-selector.component.ts b/frontend/src/app/i18n/language-selector.component.ts deleted file mode 100644 index 4cb968de..00000000 --- a/frontend/src/app/i18n/language-selector.component.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Component, OnInit, Input } from '@angular/core'; - -import { I18nService } from './i18n.service'; - -@Component({ - selector: 'app-language-selector', - templateUrl: './language-selector.component.html', - styleUrls: ['./language-selector.component.scss'], -}) -export class LanguageSelectorComponent implements OnInit { - @Input() icon = false; - - constructor(private i18nService: I18nService) {} - - ngOnInit() {} - - setLanguage(language: string) { - this.i18nService.language = language; - } - - get currentLanguage(): string { - return this.i18nService.language; - } - - get languages(): string[] { - return this.i18nService.supportedLanguages; - } -} diff --git a/frontend/src/app/layout/common/notifications/notifications.component.html b/frontend/src/app/layout/common/notifications/notifications.component.html new file mode 100644 index 00000000..5dc96587 --- /dev/null +++ b/frontend/src/app/layout/common/notifications/notifications.component.html @@ -0,0 +1,204 @@ + + + + + +
+ +
+
+ +
+
Notifications
+
+ +
+
+ + +
+ + @for ( + notification of notifications; + track trackByFn($index, notification) + ) { +
+ + @if (notification.link) { + + @if (!notification.useRouter) { + + + + } + + @if (notification.useRouter) { + + + + } + } + + + @if (!notification.link) { +
+ +
+ } + + +
+ + + + +
+
+ + + + + @if (notification.icon && !notification.image) { +
+ + +
+ } + + @if (notification.image) { + + } + +
+ @if (notification.title) { +
+ } + @if (notification.description) { +
+ } +
+ {{ notification.time | date: 'MMM dd, h:mm a' }} +
+
+
+ } + + + @if (!notifications || !notifications.length) { +
+
+ +
+
+ No notifications +
+
+ When you have notifications, they will appear here. +
+
+ } +
+
+
diff --git a/frontend/src/app/layout/common/notifications/notifications.component.ts b/frontend/src/app/layout/common/notifications/notifications.component.ts new file mode 100644 index 00000000..a6cc2dec --- /dev/null +++ b/frontend/src/app/layout/common/notifications/notifications.component.ts @@ -0,0 +1,237 @@ +import { Overlay, OverlayRef } from '@angular/cdk/overlay'; +import { TemplatePortal } from '@angular/cdk/portal'; +import { DatePipe, NgClass, NgTemplateOutlet } from '@angular/common'; +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + OnDestroy, + OnInit, + TemplateRef, + ViewChild, + ViewContainerRef, + ViewEncapsulation, +} from '@angular/core'; +import { MatButton, MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { RouterLink } from '@angular/router'; +import { NotificationsService } from 'app/layout/common/notifications/notifications.service'; +import { Notification } from 'app/layout/common/notifications/notifications.types'; +import { Subject, takeUntil } from 'rxjs'; + +@Component({ + selector: 'notifications', + templateUrl: './notifications.component.html', + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + exportAs: 'notifications', + standalone: true, + imports: [ + MatButtonModule, + MatIconModule, + MatTooltipModule, + NgClass, + NgTemplateOutlet, + RouterLink, + DatePipe, + ], +}) +export class NotificationsComponent implements OnInit, OnDestroy { + @ViewChild('notificationsOrigin') private _notificationsOrigin: MatButton; + @ViewChild('notificationsPanel') + private _notificationsPanel: TemplateRef; + + notifications: Notification[]; + unreadCount: number = 0; + private _overlayRef: OverlayRef; + private _unsubscribeAll: Subject = new Subject(); + + /** + * Constructor + */ + constructor( + private _changeDetectorRef: ChangeDetectorRef, + private _notificationsService: NotificationsService, + private _overlay: Overlay, + private _viewContainerRef: ViewContainerRef + ) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Subscribe to notification changes + this._notificationsService.notifications$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((notifications: Notification[]) => { + // Load the notifications + this.notifications = notifications; + + // Calculate the unread count + this._calculateUnreadCount(); + + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + + // Dispose the overlay + if (this._overlayRef) { + this._overlayRef.dispose(); + } + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Open the notifications panel + */ + openPanel(): void { + // Return if the notifications panel or its origin is not defined + if (!this._notificationsPanel || !this._notificationsOrigin) { + return; + } + + // Create the overlay if it doesn't exist + if (!this._overlayRef) { + this._createOverlay(); + } + + // Attach the portal to the overlay + this._overlayRef.attach( + new TemplatePortal(this._notificationsPanel, this._viewContainerRef) + ); + } + + /** + * Close the notifications panel + */ + closePanel(): void { + this._overlayRef.detach(); + } + + /** + * Mark all notifications as read + */ + markAllAsRead(): void { + // Mark all as read + this._notificationsService.markAllAsRead().subscribe(); + } + + /** + * Toggle read status of the given notification + */ + toggleRead(notification: Notification): void { + // Toggle the read status + notification.read = !notification.read; + + // Update the notification + this._notificationsService + .update(notification.id, notification) + .subscribe(); + } + + /** + * Delete the given notification + */ + delete(notification: Notification): void { + // Delete the notification + this._notificationsService.delete(notification.id).subscribe(); + } + + /** + * Track by function for ngFor loops + * + * @param index + * @param item + */ + trackByFn(index: number, item: any): any { + return item.id || index; + } + + // ----------------------------------------------------------------------------------------------------- + // @ Private methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Create the overlay + */ + private _createOverlay(): void { + // Create the overlay + this._overlayRef = this._overlay.create({ + hasBackdrop: true, + backdropClass: 'fuse-backdrop-on-mobile', + scrollStrategy: this._overlay.scrollStrategies.block(), + positionStrategy: this._overlay + .position() + .flexibleConnectedTo( + this._notificationsOrigin._elementRef.nativeElement + ) + .withLockedPosition(true) + .withPush(true) + .withPositions([ + { + originX: 'start', + originY: 'bottom', + overlayX: 'start', + overlayY: 'top', + }, + { + originX: 'start', + originY: 'top', + overlayX: 'start', + overlayY: 'bottom', + }, + { + originX: 'end', + originY: 'bottom', + overlayX: 'end', + overlayY: 'top', + }, + { + originX: 'end', + originY: 'top', + overlayX: 'end', + overlayY: 'bottom', + }, + ]), + }); + + // Detach the overlay from the portal on backdrop click + this._overlayRef.backdropClick().subscribe(() => { + this._overlayRef.detach(); + }); + } + + /** + * Calculate the unread count + * + * @private + */ + private _calculateUnreadCount(): void { + let count = 0; + + if (this.notifications && this.notifications.length) { + count = this.notifications.filter( + (notification) => !notification.read + ).length; + } + + this.unreadCount = count; + } +} diff --git a/frontend/src/app/layout/common/notifications/notifications.service.ts b/frontend/src/app/layout/common/notifications/notifications.service.ts new file mode 100644 index 00000000..1e907d5d --- /dev/null +++ b/frontend/src/app/layout/common/notifications/notifications.service.ts @@ -0,0 +1,170 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Notification } from 'app/layout/common/notifications/notifications.types'; +import { map, Observable, ReplaySubject, switchMap, take, tap } from 'rxjs'; + +@Injectable({ providedIn: 'root' }) +export class NotificationsService { + private _notifications: ReplaySubject = new ReplaySubject< + Notification[] + >(1); + + /** + * Constructor + */ + constructor(private _httpClient: HttpClient) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Getter for notifications + */ + get notifications$(): Observable { + return this._notifications.asObservable(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Get all notifications + */ + getAll(): Observable { + return this._httpClient + .get('api/common/notifications') + .pipe( + tap((notifications) => { + this._notifications.next(notifications); + }) + ); + } + + /** + * Create a notification + * + * @param notification + */ + create(notification: Notification): Observable { + return this.notifications$.pipe( + take(1), + switchMap((notifications) => + this._httpClient + .post('api/common/notifications', { + notification, + }) + .pipe( + map((newNotification) => { + // Update the notifications with the new notification + this._notifications.next([ + ...notifications, + newNotification, + ]); + + // Return the new notification from observable + return newNotification; + }) + ) + ) + ); + } + + /** + * Update the notification + * + * @param id + * @param notification + */ + update(id: string, notification: Notification): Observable { + return this.notifications$.pipe( + take(1), + switchMap((notifications) => + this._httpClient + .patch('api/common/notifications', { + id, + notification, + }) + .pipe( + map((updatedNotification: Notification) => { + // Find the index of the updated notification + const index = notifications.findIndex( + (item) => item.id === id + ); + + // Update the notification + notifications[index] = updatedNotification; + + // Update the notifications + this._notifications.next(notifications); + + // Return the updated notification + return updatedNotification; + }) + ) + ) + ); + } + + /** + * Delete the notification + * + * @param id + */ + delete(id: string): Observable { + return this.notifications$.pipe( + take(1), + switchMap((notifications) => + this._httpClient + .delete('api/common/notifications', { + params: { id }, + }) + .pipe( + map((isDeleted: boolean) => { + // Find the index of the deleted notification + const index = notifications.findIndex( + (item) => item.id === id + ); + + // Delete the notification + notifications.splice(index, 1); + + // Update the notifications + this._notifications.next(notifications); + + // Return the deleted status + return isDeleted; + }) + ) + ) + ); + } + + /** + * Mark all notifications as read + */ + markAllAsRead(): Observable { + return this.notifications$.pipe( + take(1), + switchMap((notifications) => + this._httpClient + .get('api/common/notifications/mark-all-as-read') + .pipe( + map((isUpdated: boolean) => { + // Go through all notifications and set them as read + notifications.forEach((notification, index) => { + notifications[index].read = true; + }); + + // Update the notifications + this._notifications.next(notifications); + + // Return the updated status + return isUpdated; + }) + ) + ) + ); + } +} diff --git a/frontend/src/app/layout/common/notifications/notifications.types.ts b/frontend/src/app/layout/common/notifications/notifications.types.ts new file mode 100644 index 00000000..3ebf5b60 --- /dev/null +++ b/frontend/src/app/layout/common/notifications/notifications.types.ts @@ -0,0 +1,11 @@ +export interface Notification { + id: string; + icon?: string; + image?: string; + title?: string; + description?: string; + time: string; + link?: string; + useRouter?: boolean; + read: boolean; +} diff --git a/frontend/src/app/layout/common/search/search.component.html b/frontend/src/app/layout/common/search/search.component.html new file mode 100644 index 00000000..04e4ed51 --- /dev/null +++ b/frontend/src/app/layout/common/search/search.component.html @@ -0,0 +1,234 @@ + +@if (appearance === 'bar') { + @if (!opened) { + + } + @if (opened) { +
+ + + + @if (resultSets && !resultSets.length) { + + No results found! + + } + @for ( + resultSet of resultSets; + track trackByFn($index, resultSet) + ) { + + {{ resultSet.label.toUpperCase() }} + + @for ( + result of resultSet.results; + track trackByFn($index, result) + ) { + + + @if (resultSet.id === 'contacts') { + + } + + @if (resultSet.id === 'pages') { + + } + + @if (resultSet.id === 'tasks') { + + } + + } + } + + +
+ } +} + + +@if (appearance === 'basic') { +
+ + + + + + @if (resultSets && !resultSets.length) { + + No results found! + + } + @for (resultSet of resultSets; track trackByFn($index, resultSet)) { + + {{ resultSet.label.toUpperCase() }} + + @for ( + result of resultSet.results; + track trackByFn($index, result) + ) { + + + @if (resultSet.id === 'contacts') { + + } + + @if (resultSet.id === 'pages') { + + } + + @if (resultSet.id === 'tasks') { + + } + + } + } + +
+} + + + +
+
+ @if (result.avatar) { + + } + @if (!result.avatar) { + + } +
+
+ +
+
+
+ + + +
+
+
+ {{ result.link }} +
+
+
+ + + +
+ @if (result.completed) { + + } + @if (!result.completed) { + + } +
+
+
diff --git a/frontend/src/app/layout/common/search/search.component.ts b/frontend/src/app/layout/common/search/search.component.ts new file mode 100644 index 00000000..4d9e91cb --- /dev/null +++ b/frontend/src/app/layout/common/search/search.component.ts @@ -0,0 +1,256 @@ +import { Overlay } from '@angular/cdk/overlay'; +import { NgClass, NgTemplateOutlet } from '@angular/common'; +import { HttpClient } from '@angular/common/http'; +import { + Component, + ElementRef, + EventEmitter, + HostBinding, + Input, + OnChanges, + OnDestroy, + OnInit, + Output, + Renderer2, + SimpleChanges, + ViewChild, + ViewEncapsulation, + inject, +} from '@angular/core'; +import { + FormsModule, + ReactiveFormsModule, + UntypedFormControl, +} from '@angular/forms'; +import { + MAT_AUTOCOMPLETE_SCROLL_STRATEGY, + MatAutocomplete, + MatAutocompleteModule, +} from '@angular/material/autocomplete'; +import { MatButtonModule } from '@angular/material/button'; +import { MatOptionModule } from '@angular/material/core'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { RouterLink } from '@angular/router'; +import { fuseAnimations } from '@fuse/animations/public-api'; +import { Subject, debounceTime, filter, map, takeUntil } from 'rxjs'; + +@Component({ + selector: 'search', + templateUrl: './search.component.html', + encapsulation: ViewEncapsulation.None, + exportAs: 'fuseSearch', + animations: fuseAnimations, + standalone: true, + imports: [ + MatButtonModule, + MatIconModule, + FormsModule, + MatAutocompleteModule, + ReactiveFormsModule, + MatOptionModule, + RouterLink, + NgTemplateOutlet, + MatFormFieldModule, + MatInputModule, + NgClass, + ], + providers: [ + { + provide: MAT_AUTOCOMPLETE_SCROLL_STRATEGY, + useFactory: () => { + const overlay = inject(Overlay); + return () => overlay.scrollStrategies.block(); + }, + }, + ], +}) +export class SearchComponent implements OnChanges, OnInit, OnDestroy { + @Input() appearance: 'basic' | 'bar' = 'basic'; + @Input() debounce: number = 300; + @Input() minLength: number = 2; + @Output() search: EventEmitter = new EventEmitter(); + + opened: boolean = false; + resultSets: any[]; + searchControl: UntypedFormControl = new UntypedFormControl(); + private _matAutocomplete: MatAutocomplete; + private _unsubscribeAll: Subject = new Subject(); + + /** + * Constructor + */ + constructor( + private _elementRef: ElementRef, + private _httpClient: HttpClient, + private _renderer2: Renderer2 + ) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Host binding for component classes + */ + @HostBinding('class') get classList(): any { + return { + 'search-appearance-bar': this.appearance === 'bar', + 'search-appearance-basic': this.appearance === 'basic', + 'search-opened': this.opened, + }; + } + + /** + * Setter for bar search input + * + * @param value + */ + @ViewChild('barSearchInput') + set barSearchInput(value: ElementRef) { + // If the value exists, it means that the search input + // is now in the DOM, and we can focus on the input.. + if (value) { + // Give Angular time to complete the change detection cycle + setTimeout(() => { + // Focus to the input element + value.nativeElement.focus(); + }); + } + } + + /** + * Setter for mat-autocomplete element reference + * + * @param value + */ + @ViewChild('matAutocomplete') + set matAutocomplete(value: MatAutocomplete) { + this._matAutocomplete = value; + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On changes + * + * @param changes + */ + ngOnChanges(changes: SimpleChanges): void { + // Appearance + if ('appearance' in changes) { + // To prevent any issues, close the + // search after changing the appearance + this.close(); + } + } + + /** + * On init + */ + ngOnInit(): void { + // Subscribe to the search field value changes + this.searchControl.valueChanges + .pipe( + debounceTime(this.debounce), + takeUntil(this._unsubscribeAll), + map((value) => { + // Set the resultSets to null if there is no value or + // the length of the value is smaller than the minLength + // so the autocomplete panel can be closed + if (!value || value.length < this.minLength) { + this.resultSets = null; + } + + // Continue + return value; + }), + // Filter out undefined/null/false statements and also + // filter out the values that are smaller than minLength + filter((value) => value && value.length >= this.minLength) + ) + .subscribe((value) => { + this._httpClient + .post('api/common/search', { query: value }) + .subscribe((resultSets: any) => { + // Store the result sets + this.resultSets = resultSets; + + // Execute the event + this.search.next(resultSets); + }); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * On keydown of the search input + * + * @param event + */ + onKeydown(event: KeyboardEvent): void { + // Escape + if (event.code === 'Escape') { + // If the appearance is 'bar' and the mat-autocomplete is not open, close the search + if (this.appearance === 'bar' && !this._matAutocomplete.isOpen) { + this.close(); + } + } + } + + /** + * Open the search + * Used in 'bar' + */ + open(): void { + // Return if it's already opened + if (this.opened) { + return; + } + + // Open the search + this.opened = true; + } + + /** + * Close the search + * * Used in 'bar' + */ + close(): void { + // Return if it's already closed + if (!this.opened) { + return; + } + + // Clear the search input + this.searchControl.setValue(''); + + // Close the search + this.opened = false; + } + + /** + * Track by function for ngFor loops + * + * @param index + * @param item + */ + trackByFn(index: number, item: any): any { + return item.id || index; + } +} diff --git a/frontend/src/app/layout/common/user/user.component.html b/frontend/src/app/layout/common/user/user.component.html new file mode 100644 index 00000000..58a0873a --- /dev/null +++ b/frontend/src/app/layout/common/user/user.component.html @@ -0,0 +1,82 @@ + + \ No newline at end of file diff --git a/frontend/src/app/layout/common/user/user.component.ts b/frontend/src/app/layout/common/user/user.component.ts new file mode 100644 index 00000000..24c1b376 --- /dev/null +++ b/frontend/src/app/layout/common/user/user.component.ts @@ -0,0 +1,118 @@ +import { BooleanInput } from '@angular/cdk/coercion'; +import { NgClass } from '@angular/common'; +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + Input, + OnDestroy, + OnInit, + ViewEncapsulation, +} from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatDividerModule } from '@angular/material/divider'; +import { MatIconModule } from '@angular/material/icon'; +import { MatMenuModule } from '@angular/material/menu'; +import {Router, RouterModule} from '@angular/router'; +import { UserService } from 'app/core/user/user.service'; +import { User } from 'app/core/user/user.types'; +import { Subject, takeUntil } from 'rxjs'; + +@Component({ + selector: 'user', + templateUrl: './user.component.html', + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + exportAs: 'user', + standalone: true, + imports: [ + MatButtonModule, + MatMenuModule, + MatIconModule, + NgClass, + MatDividerModule, + RouterModule, + ], +}) +export class UserComponent implements OnInit, OnDestroy { + /* eslint-disable @typescript-eslint/naming-convention */ + static ngAcceptInputType_showAvatar: BooleanInput; + /* eslint-enable @typescript-eslint/naming-convention */ + + @Input() showAvatar: boolean = true; + user: User = { + name: '', + email: '', + id: '' + }; + + private _unsubscribeAll: Subject = new Subject(); + + /** + * Constructor + */ + constructor( + private _changeDetectorRef: ChangeDetectorRef, + private _router: Router, + private _userService: UserService + ) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Subscribe to user changes + this._userService.user$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((user: User) => { + this.user = user; + + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Update the user status + * + * @param status + */ + updateUserStatus(status: string): void { + // Return if user is not available + if (!this.user) { + return; + } + + // Update the user + this._userService + .update({ + ...this.user, + status, + }) + .subscribe(); + } + + /** + * Sign out + */ + signOut(): void { + this._router.navigate(['/sign-out']); + } +} diff --git a/frontend/src/app/layout/layout.component.html b/frontend/src/app/layout/layout.component.html new file mode 100644 index 00000000..df0d49bc --- /dev/null +++ b/frontend/src/app/layout/layout.component.html @@ -0,0 +1,39 @@ + + + + + + + + + + +@if (layout === 'modern') { + +} + + + + + + +@if (layout === 'compact') { + +} + + +@if (layout === 'dense') { + +} + + +@if (layout === 'thin') { + +} + + + + + diff --git a/frontend/src/app/layout/layout.component.scss b/frontend/src/app/layout/layout.component.scss new file mode 100644 index 00000000..06b34104 --- /dev/null +++ b/frontend/src/app/layout/layout.component.scss @@ -0,0 +1,25 @@ +layout { + display: flex; + flex: 1 1 auto; + width: 100%; + max-width: 100%; + min-width: 0; + + /* Base styles for individual layouts */ + > * { + position: relative; + display: flex; + flex: 1 1 auto; + width: 100%; + } + + /* Base styles for components that load as a route */ + router-outlet { + + * { + position: relative; + display: flex; + flex: 1 1 auto; + width: 100%; + } + } +} diff --git a/frontend/src/app/layout/layout.component.ts b/frontend/src/app/layout/layout.component.ts new file mode 100644 index 00000000..097df8cb --- /dev/null +++ b/frontend/src/app/layout/layout.component.ts @@ -0,0 +1,235 @@ +import { DOCUMENT } from '@angular/common'; +import { + Component, + Inject, + OnDestroy, + OnInit, + Renderer2, + ViewEncapsulation, +} from '@angular/core'; +import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; +import { FuseConfig, FuseConfigService } from '@fuse/services/config'; +import { FuseMediaWatcherService } from '@fuse/services/media-watcher'; +import { FusePlatformService } from '@fuse/services/platform'; +import { FUSE_VERSION } from '@fuse/version'; +import { Subject, combineLatest, filter, map, takeUntil } from 'rxjs'; +import { ModernLayoutComponent } from './layouts/horizontal/modern/modern.component'; +import { CompactLayoutComponent } from './layouts/vertical/compact/compact.component'; +import { DenseLayoutComponent } from './layouts/vertical/dense/dense.component'; +import { ThinLayoutComponent } from './layouts/vertical/thin/thin.component'; + +@Component({ + selector: 'layout', + templateUrl: './layout.component.html', + styleUrls: ['./layout.component.scss'], + encapsulation: ViewEncapsulation.None, + standalone: true, + imports: [ + ModernLayoutComponent, + CompactLayoutComponent, + DenseLayoutComponent, + ThinLayoutComponent, + ], +}) +export class LayoutComponent implements OnInit, OnDestroy { + config: FuseConfig; + layout: string; + scheme: 'dark' | 'light'; + theme: string; + private _unsubscribeAll: Subject = new Subject(); + + /** + * Constructor + */ + constructor( + private _activatedRoute: ActivatedRoute, + @Inject(DOCUMENT) private _document: any, + private _renderer2: Renderer2, + private _router: Router, + private _fuseConfigService: FuseConfigService, + private _fuseMediaWatcherService: FuseMediaWatcherService, + private _fusePlatformService: FusePlatformService + ) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Set the theme and scheme based on the configuration + combineLatest([ + this._fuseConfigService.config$, + this._fuseMediaWatcherService.onMediaQueryChange$([ + '(prefers-color-scheme: dark)', + '(prefers-color-scheme: light)', + ]), + ]) + .pipe( + takeUntil(this._unsubscribeAll), + map(([config, mql]) => { + const options = { + scheme: config.scheme, + theme: config.theme, + }; + + // If the scheme is set to 'auto'... + if (config.scheme === 'auto') { + // Decide the scheme using the media query + options.scheme = mql.breakpoints[ + '(prefers-color-scheme: dark)' + ] + ? 'dark' + : 'light'; + } + + return options; + }) + ) + .subscribe((options) => { + // Store the options + this.scheme = options.scheme; + this.theme = options.theme; + + // Update the scheme and theme + this._updateScheme(); + this._updateTheme(); + }); + + // Subscribe to config changes + this._fuseConfigService.config$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((config: FuseConfig) => { + // Store the config + this.config = config; + + // Update the layout + this._updateLayout(); + }); + + // Subscribe to NavigationEnd event + this._router.events + .pipe( + filter((event) => event instanceof NavigationEnd), + takeUntil(this._unsubscribeAll) + ) + .subscribe(() => { + // Update the layout + this._updateLayout(); + }); + + // Set the app version + this._renderer2.setAttribute( + this._document.querySelector('[ng-version]'), + 'fuse-version', + FUSE_VERSION + ); + + // Set the OS name + this._renderer2.addClass( + this._document.body, + this._fusePlatformService.osName + ); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Private methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Update the selected layout + */ + private _updateLayout(): void { + // Get the current activated route + let route = this._activatedRoute; + while (route.firstChild) { + route = route.firstChild; + } + + // 1. Set the layout from the config + this.layout = this.config.layout; + + // 2. Get the query parameter from the current route and + // set the layout and save the layout to the config + const layoutFromQueryParam = route.snapshot.queryParamMap.get('layout'); + if (layoutFromQueryParam) { + this.layout = layoutFromQueryParam; + if (this.config) { + this.config.layout = layoutFromQueryParam; + } + } + + // 3. Iterate through the paths and change the layout as we find + // a config for it. + // + // The reason we do this is that there might be empty grouping + // paths or componentless routes along the path. Because of that, + // we cannot just assume that the layout configuration will be + // in the last path's config or in the first path's config. + // + // So, we get all the paths that matched starting from root all + // the way to the current activated route, walk through them one + // by one and change the layout as we find the layout config. This + // way, layout configuration can live anywhere within the path and + // we won't miss it. + // + // Also, this will allow overriding the layout in any time so we + // can have different layouts for different routes. + const paths = route.pathFromRoot; + paths.forEach((path) => { + // Check if there is a 'layout' data + if ( + path.routeConfig && + path.routeConfig.data && + path.routeConfig.data.layout + ) { + // Set the layout + this.layout = path.routeConfig.data.layout; + } + }); + } + + /** + * Update the selected scheme + * + * @private + */ + private _updateScheme(): void { + // Remove class names for all schemes + this._document.body.classList.remove('light', 'dark'); + + // Add class name for the currently selected scheme + this._document.body.classList.add(this.scheme); + } + + /** + * Update the selected theme + * + * @private + */ + private _updateTheme(): void { + // Find the class name for the previously selected theme and remove it + this._document.body.classList.forEach((className: string) => { + if (className.startsWith('theme-')) { + this._document.body.classList.remove( + className, + className.split('-')[1] + ); + } + }); + + // Add class name for the currently selected theme + this._document.body.classList.add(this.theme); + } +} diff --git a/frontend/src/app/layout/layouts/horizontal/modern/modern.component.html b/frontend/src/app/layout/layouts/horizontal/modern/modern.component.html new file mode 100644 index 00000000..1c7e374f --- /dev/null +++ b/frontend/src/app/layout/layouts/horizontal/modern/modern.component.html @@ -0,0 +1,83 @@ + + + + +@if (isScreenSmall) { + + + + +
+ Logo image +
+
+
+} + + +
+ +
+ @if (!isScreenSmall) { + +
+ + Sophia +
+ + + } + + @if (isScreenSmall) { + + } + +
+ + + +
+
+ + +
+ + @if (true) { + + } +
+
diff --git a/frontend/src/app/layout/layouts/horizontal/modern/modern.component.ts b/frontend/src/app/layout/layouts/horizontal/modern/modern.component.ts new file mode 100644 index 00000000..a3a4a778 --- /dev/null +++ b/frontend/src/app/layout/layouts/horizontal/modern/modern.component.ts @@ -0,0 +1,117 @@ +import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { ActivatedRoute, Router, RouterOutlet } from '@angular/router'; +import { FuseFullscreenComponent } from '@fuse/components/fullscreen'; +import { FuseLoadingBarComponent } from '@fuse/components/loading-bar'; +import { + FuseHorizontalNavigationComponent, + FuseNavigationService, + FuseVerticalNavigationComponent, +} from '@fuse/components/navigation'; +import { FuseMediaWatcherService } from '@fuse/services/media-watcher'; +import { NavigationService } from 'app/core/navigation/navigation.service'; +import { Navigation } from 'app/core/navigation/navigation.types'; +import { NotificationsComponent } from 'app/layout/common/notifications/notifications.component'; +import { UserComponent } from 'app/layout/common/user/user.component'; +import { Subject, takeUntil } from 'rxjs'; + +@Component({ + selector: 'modern-layout', + templateUrl: './modern.component.html', + encapsulation: ViewEncapsulation.None, + standalone: true, + imports: [ + FuseLoadingBarComponent, + FuseVerticalNavigationComponent, + FuseHorizontalNavigationComponent, + MatButtonModule, + MatIconModule, + FuseFullscreenComponent, + NotificationsComponent, + UserComponent, + RouterOutlet, + ], +}) +export class ModernLayoutComponent implements OnInit, OnDestroy { + isScreenSmall: boolean; + navigation: Navigation; + private _unsubscribeAll: Subject = new Subject(); + + /** + * Constructor + */ + constructor( + private _activatedRoute: ActivatedRoute, + private _router: Router, + private _navigationService: NavigationService, + private _fuseMediaWatcherService: FuseMediaWatcherService, + private _fuseNavigationService: FuseNavigationService + ) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Getter for current year + */ + get currentYear(): number { + return new Date().getFullYear(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Subscribe to navigation data + this._navigationService.navigation$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((navigation: Navigation) => { + this.navigation = navigation; + }); + + // Subscribe to media changes + this._fuseMediaWatcherService.onMediaChange$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(({ matchingAliases }) => { + // Check if the screen is small + this.isScreenSmall = !matchingAliases.includes('md'); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle navigation + * + * @param name + */ + toggleNavigation(name: string): void { + // Get the navigation + const navigation = + this._fuseNavigationService.getComponent( + name + ); + + if (navigation) { + // Toggle the opened status + navigation.toggle(); + } + } +} diff --git a/frontend/src/app/layout/layouts/vertical/compact/compact.component.html b/frontend/src/app/layout/layouts/vertical/compact/compact.component.html new file mode 100644 index 00000000..1f1770cd --- /dev/null +++ b/frontend/src/app/layout/layouts/vertical/compact/compact.component.html @@ -0,0 +1,49 @@ + + + + + + + + +
+ + Sophia +
+
+
+ + +
+ +
+ + + +
+ + + +
+
+ + +
+ + @if (true) { + + } +
+
diff --git a/frontend/src/app/layout/layouts/vertical/compact/compact.component.ts b/frontend/src/app/layout/layouts/vertical/compact/compact.component.ts new file mode 100644 index 00000000..d380e3c4 --- /dev/null +++ b/frontend/src/app/layout/layouts/vertical/compact/compact.component.ts @@ -0,0 +1,115 @@ +import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { ActivatedRoute, Router, RouterOutlet } from '@angular/router'; +import { FuseFullscreenComponent } from '@fuse/components/fullscreen'; +import { FuseLoadingBarComponent } from '@fuse/components/loading-bar'; +import { + FuseNavigationService, + FuseVerticalNavigationComponent, +} from '@fuse/components/navigation'; +import { FuseMediaWatcherService } from '@fuse/services/media-watcher'; +import { NavigationService } from 'app/core/navigation/navigation.service'; +import { Navigation } from 'app/core/navigation/navigation.types'; +import { NotificationsComponent } from 'app/layout/common/notifications/notifications.component'; +import { UserComponent } from 'app/layout/common/user/user.component'; +import { Subject, takeUntil } from 'rxjs'; + +@Component({ + selector: 'compact-layout', + templateUrl: './compact.component.html', + encapsulation: ViewEncapsulation.None, + standalone: true, + imports: [ + FuseLoadingBarComponent, + MatButtonModule, + MatIconModule, + FuseFullscreenComponent, + NotificationsComponent, + UserComponent, + RouterOutlet, + FuseVerticalNavigationComponent, + ], +}) +export class CompactLayoutComponent implements OnInit, OnDestroy { + isScreenSmall: boolean; + navigation: Navigation; + private _unsubscribeAll: Subject = new Subject(); + + /** + * Constructor + */ + constructor( + private _activatedRoute: ActivatedRoute, + private _router: Router, + private _navigationService: NavigationService, + private _fuseMediaWatcherService: FuseMediaWatcherService, + private _fuseNavigationService: FuseNavigationService + ) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Getter for current year + */ + get currentYear(): number { + return new Date().getFullYear(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Subscribe to navigation data + this._navigationService.navigation$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((navigation: Navigation) => { + this.navigation = navigation; + }); + + // Subscribe to media changes + this._fuseMediaWatcherService.onMediaChange$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(({ matchingAliases }) => { + // Check if the screen is small + this.isScreenSmall = !matchingAliases.includes('md'); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle navigation + * + * @param name + */ + toggleNavigation(name: string): void { + // Get the navigation + const navigation = + this._fuseNavigationService.getComponent( + name + ); + + if (navigation) { + // Toggle the opened status + navigation.toggle(); + } + } +} diff --git a/frontend/src/app/layout/layouts/vertical/dense/dense.component.html b/frontend/src/app/layout/layouts/vertical/dense/dense.component.html new file mode 100644 index 00000000..e0d1876b --- /dev/null +++ b/frontend/src/app/layout/layouts/vertical/dense/dense.component.html @@ -0,0 +1,64 @@ + + + + + + + + +
+ + Sophia +
+
+
+ + +
+ +
+
+ + + + +
+ +
+ + + +
+
+ + +
+ + @if (true) { + + } +
+
diff --git a/frontend/src/app/layout/layouts/vertical/dense/dense.component.ts b/frontend/src/app/layout/layouts/vertical/dense/dense.component.ts new file mode 100644 index 00000000..350e7c21 --- /dev/null +++ b/frontend/src/app/layout/layouts/vertical/dense/dense.component.ts @@ -0,0 +1,129 @@ +import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { ActivatedRoute, Router, RouterOutlet } from '@angular/router'; +import { FuseFullscreenComponent } from '@fuse/components/fullscreen'; +import { FuseLoadingBarComponent } from '@fuse/components/loading-bar'; +import { + FuseNavigationService, + FuseVerticalNavigationComponent, +} from '@fuse/components/navigation'; +import { FuseMediaWatcherService } from '@fuse/services/media-watcher'; +import { NavigationService } from 'app/core/navigation/navigation.service'; +import { Navigation } from 'app/core/navigation/navigation.types'; +import { NotificationsComponent } from 'app/layout/common/notifications/notifications.component'; +import { UserComponent } from 'app/layout/common/user/user.component'; +import { Subject, takeUntil } from 'rxjs'; + +@Component({ + selector: 'dense-layout', + templateUrl: './dense.component.html', + encapsulation: ViewEncapsulation.None, + standalone: true, + imports: [ + FuseLoadingBarComponent, + FuseVerticalNavigationComponent, + MatButtonModule, + MatIconModule, + FuseFullscreenComponent, + NotificationsComponent, + UserComponent, + RouterOutlet, + ], +}) +export class DenseLayoutComponent implements OnInit, OnDestroy { + isScreenSmall: boolean; + navigation: Navigation; + navigationAppearance: 'default' | 'dense' = 'dense'; + private _unsubscribeAll: Subject = new Subject(); + + /** + * Constructor + */ + constructor( + private _activatedRoute: ActivatedRoute, + private _router: Router, + private _navigationService: NavigationService, + private _fuseMediaWatcherService: FuseMediaWatcherService, + private _fuseNavigationService: FuseNavigationService + ) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Getter for current year + */ + get currentYear(): number { + return new Date().getFullYear(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Subscribe to navigation data + this._navigationService.navigation$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((navigation: Navigation) => { + this.navigation = navigation; + }); + + // Subscribe to media changes + this._fuseMediaWatcherService.onMediaChange$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(({ matchingAliases }) => { + // Check if the screen is small + this.isScreenSmall = !matchingAliases.includes('md'); + + // Change the navigation appearance + this.navigationAppearance = this.isScreenSmall + ? 'default' + : 'dense'; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle navigation + * + * @param name + */ + toggleNavigation(name: string): void { + // Get the navigation + const navigation = + this._fuseNavigationService.getComponent( + name + ); + + if (navigation) { + // Toggle the opened status + navigation.toggle(); + } + } + + /** + * Toggle the navigation appearance + */ + toggleNavigationAppearance(): void { + this.navigationAppearance = + this.navigationAppearance === 'default' ? 'dense' : 'default'; + } +} diff --git a/frontend/src/app/layout/layouts/vertical/thin/thin.component.html b/frontend/src/app/layout/layouts/vertical/thin/thin.component.html new file mode 100644 index 00000000..d80e4421 --- /dev/null +++ b/frontend/src/app/layout/layouts/vertical/thin/thin.component.html @@ -0,0 +1,53 @@ + + + + + + + + +
+ + Sophia +
+
+
+ + +
+ +
+ + + +
+ + + +
+
+ + +
+ + @if (true) { + + } +
+
diff --git a/frontend/src/app/layout/layouts/vertical/thin/thin.component.ts b/frontend/src/app/layout/layouts/vertical/thin/thin.component.ts new file mode 100644 index 00000000..15fa5d7a --- /dev/null +++ b/frontend/src/app/layout/layouts/vertical/thin/thin.component.ts @@ -0,0 +1,115 @@ +import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { ActivatedRoute, Router, RouterOutlet } from '@angular/router'; +import { FuseFullscreenComponent } from '@fuse/components/fullscreen'; +import { FuseLoadingBarComponent } from '@fuse/components/loading-bar'; +import { + FuseNavigationService, + FuseVerticalNavigationComponent, +} from '@fuse/components/navigation'; +import { FuseMediaWatcherService } from '@fuse/services/media-watcher'; +import { NavigationService } from 'app/core/navigation/navigation.service'; +import { Navigation } from 'app/core/navigation/navigation.types'; +import { NotificationsComponent } from 'app/layout/common/notifications/notifications.component'; +import { UserComponent } from 'app/layout/common/user/user.component'; +import { Subject, takeUntil } from 'rxjs'; + +@Component({ + selector: 'thin-layout', + templateUrl: './thin.component.html', + encapsulation: ViewEncapsulation.None, + standalone: true, + imports: [ + FuseLoadingBarComponent, + FuseVerticalNavigationComponent, + MatButtonModule, + MatIconModule, + FuseFullscreenComponent, + NotificationsComponent, + UserComponent, + RouterOutlet, + ], +}) +export class ThinLayoutComponent implements OnInit, OnDestroy { + isScreenSmall: boolean; + navigation: Navigation; + private _unsubscribeAll: Subject = new Subject(); + + /** + * Constructor + */ + constructor( + private _activatedRoute: ActivatedRoute, + private _router: Router, + private _navigationService: NavigationService, + private _fuseMediaWatcherService: FuseMediaWatcherService, + private _fuseNavigationService: FuseNavigationService + ) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Getter for current year + */ + get currentYear(): number { + return new Date().getFullYear(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Subscribe to navigation data + this._navigationService.navigation$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((navigation: Navigation) => { + this.navigation = navigation; + }); + + // Subscribe to media changes + this._fuseMediaWatcherService.onMediaChange$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(({ matchingAliases }) => { + // Check if the screen is small + this.isScreenSmall = !matchingAliases.includes('md'); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle navigation + * + * @param name + */ + toggleNavigation(name: string): void { + // Get the navigation + const navigation = + this._fuseNavigationService.getComponent( + name + ); + + if (navigation) { + // Toggle the opened status + navigation.toggle(); + } + } +} diff --git a/frontend/src/app/material.module.ts b/frontend/src/app/material.module.ts deleted file mode 100644 index ca2dc6ca..00000000 --- a/frontend/src/app/material.module.ts +++ /dev/null @@ -1,99 +0,0 @@ -/* - * This module imports and re-exports all Angular Material modules for convenience, - * so only 1 module import is needed in your feature modules. - * See https://material.angular.io/guide/getting-started#step-3-import-the-component-modules. - * - * To optimize your production builds, you should only import the components used in your app. - */ - -import { NgModule } from '@angular/core'; -import { - MatCommonModule, - MatLineModule, - MatNativeDateModule, - MatOptionModule, - MatPseudoCheckboxModule, - MatRippleModule, -} from '@angular/material/core'; -import { MatAutocompleteModule } from '@angular/material/autocomplete'; -import { MatBadgeModule } from '@angular/material/badge'; -import { MatButtonModule } from '@angular/material/button'; -import { MatButtonToggleModule } from '@angular/material/button-toggle'; -import { MatCardModule } from '@angular/material/card'; -import { MatCheckboxModule } from '@angular/material/checkbox'; -import { MatChipsModule } from '@angular/material/chips'; -import { MatDatepickerModule } from '@angular/material/datepicker'; -import { MatDialogModule } from '@angular/material/dialog'; -import { MatDividerModule } from '@angular/material/divider'; -import { MatExpansionModule } from '@angular/material/expansion'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatGridListModule } from '@angular/material/grid-list'; -import { MatIconModule } from '@angular/material/icon'; -import { MatInputModule } from '@angular/material/input'; -import { MatListModule } from '@angular/material/list'; -import { MatMenuModule } from '@angular/material/menu'; -import { MatPaginatorModule } from '@angular/material/paginator'; -import { MatProgressBarModule } from '@angular/material/progress-bar'; -import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; -import { MatRadioModule } from '@angular/material/radio'; -import { MatSelectModule } from '@angular/material/select'; -import { MatSidenavModule } from '@angular/material/sidenav'; -import { MatSlideToggleModule } from '@angular/material/slide-toggle'; -import { MatSliderModule } from '@angular/material/slider'; -import { MatSnackBarModule } from '@angular/material/snack-bar'; -import { MatSortModule } from '@angular/material/sort'; -import { MatStepperModule } from '@angular/material/stepper'; -import { MatTableModule } from '@angular/material/table'; -import { MatTabsModule } from '@angular/material/tabs'; -import { MatToolbarModule } from '@angular/material/toolbar'; -import { MatTooltipModule } from '@angular/material/tooltip'; -import { MatTreeModule } from '@angular/material/tree'; -import { ReactiveFormsModule } from '@angular/forms'; - -@NgModule({ - exports: [ - MatAutocompleteModule, - MatBadgeModule, - MatButtonModule, - MatButtonToggleModule, - MatCardModule, - MatCheckboxModule, - MatChipsModule, - MatCommonModule, - MatTableModule, - MatTableModule, - MatDatepickerModule, - MatDialogModule, - MatDividerModule, - MatExpansionModule, - MatFormFieldModule, - MatGridListModule, - MatIconModule, - MatInputModule, - MatLineModule, - MatListModule, - MatMenuModule, - MatNativeDateModule, - MatOptionModule, - MatPaginatorModule, - MatProgressBarModule, - MatProgressSpinnerModule, - MatPseudoCheckboxModule, - MatRadioModule, - MatRippleModule, - MatSelectModule, - MatSidenavModule, - MatSlideToggleModule, - MatSliderModule, - MatSnackBarModule, - MatSortModule, - MatStepperModule, - MatTableModule, - MatTabsModule, - MatToolbarModule, - MatTooltipModule, - MatTreeModule, - ReactiveFormsModule, - ], -}) -export class MaterialModule {} diff --git a/frontend/src/app/mock-api/apps/academy/api.ts b/frontend/src/app/mock-api/apps/academy/api.ts new file mode 100644 index 00000000..7e41c014 --- /dev/null +++ b/frontend/src/app/mock-api/apps/academy/api.ts @@ -0,0 +1,79 @@ +import { Injectable } from '@angular/core'; +import { FuseMockApiService } from '@fuse/lib/mock-api/mock-api.service'; +import { + categories as categoriesData, + courses as coursesData, + demoCourseSteps as demoCourseStepsData, +} from 'app/mock-api/apps/academy/data'; +import { cloneDeep } from 'lodash-es'; + +@Injectable({ providedIn: 'root' }) +export class AcademyMockApi { + private _categories: any[] = categoriesData; + private _courses: any[] = coursesData; + private _demoCourseSteps: any[] = demoCourseStepsData; + + /** + * Constructor + */ + constructor(private _fuseMockApiService: FuseMockApiService) { + // Register Mock API handlers + this.registerHandlers(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Register Mock API handlers + */ + registerHandlers(): void { + // ----------------------------------------------------------------------------------------------------- + // @ Categories - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onGet('api/apps/academy/categories') + .reply(() => { + // Clone the categories + const categories = cloneDeep(this._categories); + + // Sort the categories alphabetically by title + categories.sort((a, b) => a.title.localeCompare(b.title)); + + return [200, categories]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Courses - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService.onGet('api/apps/academy/courses').reply(() => { + // Clone the courses + const courses = cloneDeep(this._courses); + + return [200, courses]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Course - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onGet('api/apps/academy/courses/course') + .reply(({ request }) => { + // Get the id from the params + const id = request.params.get('id'); + + // Clone the courses and steps + const courses = cloneDeep(this._courses); + const steps = cloneDeep(this._demoCourseSteps); + + // Find the course and attach steps to it + const course = courses.find((item) => item.id === id); + if (course) { + course.steps = steps; + } + + return [200, course]; + }); + } +} diff --git a/frontend/src/app/mock-api/apps/academy/data.ts b/frontend/src/app/mock-api/apps/academy/data.ts new file mode 100644 index 00000000..fcc09cf5 --- /dev/null +++ b/frontend/src/app/mock-api/apps/academy/data.ts @@ -0,0 +1,724 @@ +/* eslint-disable */ +export const categories = [ + { + id: '9a67dff7-3c38-4052-a335-0cef93438ff6', + title: 'Web', + slug: 'web', + }, + { + id: 'a89672f5-e00d-4be4-9194-cb9d29f82165', + title: 'Firebase', + slug: 'firebase', + }, + { + id: '02f42092-bb23-4552-9ddb-cfdcc235d48f', + title: 'Cloud', + slug: 'cloud', + }, + { + id: '5648a630-979f-4403-8c41-fc9790dea8cd', + title: 'Android', + slug: 'android', + }, +]; +export const courses = [ + { + id: '694e4e5f-f25f-470b-bd0e-26b1d4f64028', + title: 'Basics of Angular', + slug: 'basics-of-angular', + description: 'Introductory course for Angular and framework basics', + category: 'web', + duration: 30, + totalSteps: 11, + updatedAt: 'Jun 28, 2021', + featured: true, + progress: { + currentStep: 3, + completed: 2, + }, + }, + { + id: 'f924007a-2ee9-470b-a316-8d21ed78277f', + title: 'Basics of TypeScript', + slug: 'basics-of-typeScript', + description: 'Beginner course for Typescript and its basics', + category: 'web', + duration: 60, + totalSteps: 11, + updatedAt: 'Nov 01, 2021', + featured: true, + progress: { + currentStep: 5, + completed: 3, + }, + }, + { + id: '0c06e980-abb5-4ba7-ab65-99a228cab36b', + title: 'Android N: Quick Settings', + slug: 'android-n-quick-settings', + description: 'Step by step guide for Android N: Quick Settings', + category: 'android', + duration: 120, + totalSteps: 11, + updatedAt: 'May 08, 2021', + featured: false, + progress: { + currentStep: 10, + completed: 1, + }, + }, + { + id: '1b9a9acc-9a36-403e-a1e7-b11780179e38', + title: 'Build an App for the Google Assistant with Firebase', + slug: 'build-an-app-for-the-google-assistant-with-firebase', + description: 'Dive deep into Google Assistant apps using Firebase', + category: 'firebase', + duration: 30, + totalSteps: 11, + updatedAt: 'Jan 09, 2021', + featured: false, + progress: { + currentStep: 4, + completed: 3, + }, + }, + { + id: '55eb415f-3f4e-4853-a22b-f0ae91331169', + title: 'Keep Sensitive Data Safe and Private', + slug: 'keep-sensitive-data-safe-and-private', + description: 'Learn how to keep your important data safe and private', + category: 'android', + duration: 45, + totalSteps: 11, + updatedAt: 'Jan 14, 2021', + featured: false, + progress: { + currentStep: 6, + completed: 0, + }, + }, + { + id: 'fad2ab23-1011-4028-9a54-e52179ac4a50', + title: "Manage Your Pivotal Cloud Foundry App's Using Apigee Edge", + slug: 'manage-your-pivotal-cloud-foundry-apps-using-apigee-Edge', + description: 'Introductory course for Pivotal Cloud Foundry App', + category: 'cloud', + duration: 90, + totalSteps: 11, + updatedAt: 'Jun 24, 2021', + featured: false, + progress: { + currentStep: 6, + completed: 0, + }, + }, + { + id: 'c4bc107b-edc4-47a7-a7a8-4fb09732e794', + title: 'Build a PWA Using Workbox', + slug: 'build-a-pwa-using-workbox', + description: 'Step by step guide for building a PWA using Workbox', + category: 'web', + duration: 120, + totalSteps: 11, + updatedAt: 'Nov 19, 2021', + featured: false, + progress: { + currentStep: 0, + completed: 0, + }, + }, + { + id: '1449f945-d032-460d-98e3-406565a22293', + title: 'Cloud Functions for Firebase', + slug: 'cloud-functions-for-firebase', + description: 'Beginners guide of Firebase Cloud Functions', + category: 'firebase', + duration: 45, + totalSteps: 11, + updatedAt: 'Jul 11, 2021', + featured: false, + progress: { + currentStep: 3, + completed: 1, + }, + }, + { + id: 'f05e08ab-f3e3-4597-a032-6a4b69816f24', + title: 'Building a gRPC Service with Java', + slug: 'building-a-grpc-service-with-java', + description: 'Learn more about building a gRPC Service with Java', + category: 'cloud', + duration: 30, + totalSteps: 11, + updatedAt: 'Mar 13, 2021', + featured: false, + progress: { + currentStep: 0, + completed: 1, + }, + }, + { + id: '181728f4-87c8-45c5-b9cc-92265bcd2f4d', + title: 'Looking at Campaign Finance with BigQuery', + slug: 'looking-at-campaign-finance-with-bigquery', + description: 'Dive deep into BigQuery: Campaign Finance', + category: 'cloud', + duration: 60, + totalSteps: 11, + updatedAt: 'Nov 01, 2021', + featured: false, + progress: { + currentStep: 0, + completed: 0, + }, + }, + { + id: 'fcbfedbf-6187-4b3b-89d3-1a7cb4e11616', + title: 'Personalize Your iOS App with Firebase User Management', + slug: 'personalize-your-ios-app-with-firebase-user-management', + description: + 'Dive deep into User Management on iOS apps using Firebase', + category: 'firebase', + duration: 90, + totalSteps: 11, + updatedAt: 'Aug 08, 2021', + featured: false, + progress: { + currentStep: 0, + completed: 0, + }, + }, + { + id: '5213f6a1-1dd7-4b1d-b6e9-ffb7af534f28', + title: 'Customize Network Topology with Subnetworks', + slug: 'customize-network-topology-with-subnetworks', + description: 'Dive deep into Network Topology with Subnetworks', + category: 'web', + duration: 45, + totalSteps: 11, + updatedAt: 'May 12, 2021', + featured: false, + progress: { + currentStep: 0, + completed: 0, + }, + }, + { + id: '02992ac9-d1a3-4167-b70e-8a1d5b5ba253', + title: 'Building Beautiful UIs with Flutter', + slug: 'building-beautiful-uis-with-flutter', + description: + "Dive deep into Flutter's hidden secrets for creating beautiful UIs", + category: 'web', + duration: 90, + totalSteps: 11, + updatedAt: 'Sep 18, 2021', + featured: false, + progress: { + currentStep: 8, + completed: 2, + }, + }, + { + id: '2139512f-41fb-4a4a-841a-0b4ac034f9b4', + title: 'Firebase Android', + slug: 'firebase-android', + description: 'Beginners guide of Firebase for Android', + category: 'android', + duration: 45, + totalSteps: 11, + updatedAt: 'Apr 24, 2021', + featured: false, + progress: { + currentStep: 0, + completed: 0, + }, + }, + { + id: '65e0a0e0-d8c0-4117-a3cb-eb74f8e28809', + title: 'Simulating a Thread Network Using OpenThread', + slug: 'simulating-a-thread-network-using-openthread', + description: + 'Introductory course for OpenThread and Simulating a Thread Network', + category: 'web', + duration: 45, + totalSteps: 11, + updatedAt: 'Jun 05, 2021', + featured: false, + progress: { + currentStep: 0, + completed: 0, + }, + }, + { + id: 'c202ebc9-9be3-433a-9d38-7003b3ed7b7a', + title: 'Your First Progressive Web App', + slug: 'your-first-progressive-web-app', + description: 'Step by step guide for creating a PWA from scratch', + category: 'web', + duration: 30, + totalSteps: 11, + updatedAt: 'Oct 14, 2021', + featured: false, + progress: { + currentStep: 0, + completed: 0, + }, + }, + { + id: '980ae7da-9f77-4e30-aa98-1b1ea594e775', + title: 'Launch Cloud Datalab', + slug: 'launch-cloud-datalab', + description: 'From start to finish: Launch Cloud Datalab', + category: 'cloud', + duration: 60, + totalSteps: 11, + updatedAt: 'Dec 16, 2021', + featured: false, + progress: { + currentStep: 0, + completed: 0, + }, + }, + { + id: 'c9748ea9-4117-492c-bdb2-55085b515978', + title: 'Cloud Firestore', + slug: 'cloud-firestore', + description: 'Step by step guide for setting up Cloud Firestore', + category: 'firebase', + duration: 90, + totalSteps: 11, + updatedAt: 'Apr 04, 2021', + featured: false, + progress: { + currentStep: 2, + completed: 0, + }, + }, +]; +export const demoCourseContent = ` +

+ Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusamus aperiam lab et fugiat id magnam minus nemo quam + voluptatem. Culpa deleniti explica nisi quod soluta. +

+

+ Alias animi labque, deserunt distinctio eum excepturi fuga iure labore magni molestias mollitia natus, officia pofro + quis sunt temporibus veritatis voluptatem, voluptatum. Aut blanditiis esse et illum maxim, obcaecati possimus + voluptate! Accusamus adipisci amet aperiam, assumenda consequuntur fugiat inventore iusto magnam molestias + natus necessitatibus, nulla pariatur. +

+

+ Amet distinctio enim itaque minima minus nesciunt recusandae soluta voluptatibus: +

+
+

+ Ad aliquid amet asperiores lab distinctio doloremque eaque, exercitationem explicabo, minus mollitia + natus necessitatibus odio omnis pofro rem. +

+
+

+ Alias architecto asperiores, dignissimos illum ipsam ipsum itaque, natus necessitatibus officiis, perferendis quae + sed ullam veniam vitae voluptas! Magni, nisi, quis! A accusamus animi commodi, consectetur distinctio + eaque, eos excepturi illum laboriosam maiores nam natus nulla officiis perspiciatis rem reprehenderit sed + tenetur veritatis. +

+

+ Consectetur dicta enim error eveniet expedita, facere in itaque labore natus quasi? Ad consectetur + eligendi facilis magni quae quis, quo temporibus voluptas voluptate voluptatem! +

+

+ Adipisci alias animi debitis eos et impedit maiores, modi nam nobis officia optio perspiciatis, rerum. + Accusantium esse nostrum odit quis quo: +

+
h1 a {{'{'}}
+    display: block;
+    width: 300px;
+    height: 80px;
+{{'}'}}
+

+ Accusantium aut autem, lab deleniti eaque fugiat fugit id ipsa iste molestiae, + necessitatibus nemo quasi + . +

+
+

+ Accusantium aspernatur autem enim +

+

+ Blanditiis, fugit voluptate! Assumenda blanditiis consectetur, labque cupiditate ducimus eaque earum, fugiat illum + ipsa, necessitatibus omnis quaerat reiciendis totam. Architecto, facere illum molestiae nihil nulla + quibusdam quidem vel! Atque blanditiis deserunt. +

+

+ Debitis deserunt doloremque labore laboriosam magni minus odit: +

+
    +
  1. Asperiores dicta esse maiores nobis officiis.
  2. +
  3. Accusamus aliquid debitis dolore illo ipsam molettiae possimus.
  4. +
  5. Magnam mollitia pariatur perspiciatis quasi quidem tenetur voluptatem! Adipisci aspernatur assumenda dicta.
  6. +
+

+ Animi fugit incidunt iure magni maiores molestias. +

+

+ Consequatur iusto soluta +

+

+ Aliquid asperiores corporis — deserunt dolorum ducimus eius eligendi explicabo quaerat suscipit voluptas. +

+

+ Deserunt dolor eos et illum laborum magni molestiae mollitia: +

+
+

Autem beatae consectetur consequatur, facere, facilis fugiat id illo, impedit numquam optio quis sunt ducimus illo.

+
+

+ Adipisci consequuntur doloribus facere in ipsam maxime molestias pofro quam: +

+
+ +
+ Accusamus blanditiis labque delectus esse et eum excepturi, impedit ipsam iste maiores minima mollitia, nihil obcaecati + placeat quaerat qui quidem sint unde! +
+
+

+ A beatae lab deleniti explicabo id inventore magni nisi omnis placeat praesentium quibusdam: +

+
    +
  • Dolorem eaque laboriosam omnis praesentium.
  • +
  • Atque debitis delectus distinctio doloremque.
  • +
  • Fuga illo impedit minima mollitia neque obcaecati.
  • +
+

+ Consequ eius eum excepturi explicabo. +

+

+ Adipisicing elit atque impedit? +

+

+ Atque distinctio doloremque ea qui quo, repellendus. +

+

+ Delectus deserunt explicabo facilis numquam quasi! Laboriosam, magni, quisquam. Aut, blanditiis commodi distinctio, facere fuga + hic itaque iure labore laborum maxime nemo neque provident quos recusandae sequi veritatis illum inventore iure qui rerum sapiente. +

+

+ Accusamus iusto sint aperiam consectetur … +

+

+ Aliquid assumenda ipsa nam odit pofro quaerat, quasi recusandae sint! Aut, esse explicabo facilis fugit illum iure magni + necessitatibus odio quas. +

+
    +
  • +

    Dolore natus placeat rem atque dignissimos laboriosam.

    +

    + Amet repudiandae voluptates architecto dignissimos repellendus voluptas dignissimos eveniet itaque maiores natus. +

    +

    + Accusamus aliquam debitis delectus dolorem ducimus enim eos, exercitationem fugiat id iusto nostrum quae quos + recusandae reiciendis rerum sequi temporibus veniam vero? Accusantium culpa, cupiditate ducimus eveniet id maiores modi + mollitia nisi aliquid dolorum ducimus et illo in. +

    +
  • +
  • +

    Ab amet deleniti dolor, et hic optio placeat.

    +

    + Accusantium ad alias beatae, consequatur consequuntur eos error eveniet expedita fuga laborum libero maxime nulla pofro + praesentium rem rerum saepe soluta ullam vero, voluptas? Architecto at debitis, doloribus harum iure libero natus odio + optio soluta veritatis voluptate. +

    +
  • +
  • +

    At aut consectetur nam necessitatibus neque nesciunt.

    +

    + Aut dignissimos labore nobis nostrum optio! Dolor id minima velit voluptatibus. Aut consequuntur eum exercitationem + fuga, harum id impedit molestiae natus neque numquam perspiciatis quam rem voluptatum. +

    +
  • +
+

+ Animi aperiam autem labque dolore enim ex expedita harum hic id impedit ipsa laborum modi mollitia non perspiciatis quae ratione. +

+

+ Alias eos excepturi facilis fugit. +

+

+ Alias asperiores, aspernatur corporis + delectus + est + facilis + inventore dolore + ipsa nobis nostrum officia quia, veritatis vero! At dolore est nesciunt numquam quam. Ab animi architecto aut, dignissimos + eos est eum explicabo. +

+

+ Adipisci autem consequuntur labque cupiditate dolor ducimus fuga neque nesciunt: +

+
module.exports = {{'{'}}
+    purge: [],
+    theme: {{'{'}}
+        extend: {{'{}'}},
+    },
+    variants: {{'{}'}},
+    plugins: [],
+{{'}'}}
+

+ Aliquid aspernatur eius fugit hic iusto. +

+

+ Dolorum ducimus expedita? +

+

+ Culpa debitis explicabo maxime minus quaerat reprehenderit temporibus! Asperiores, cupiditate ducimus esse est expedita fuga hic + ipsam necessitatibus placeat possimus? Amet animi aut consequuntur earum eveniet. +

+
    +
  1. + Aspernatur at beatae corporis debitis. +
      +
    • + Aperiam assumenda commodi lab dicta eius, “fugit ipsam“ itaque iure molestiae nihil numquam, officia omnis quia + repellendus sapiente sed. +
    • +
    • + Nulla odio quod saepe accusantium, adipisci autem blanditiis lab doloribus. +
    • +
    • + Explicabo facilis iusto molestiae nisi nostrum obcaecati officia. +
    • +
    +
  2. +
  3. + Nobis odio officiis optio quae quis quisquam quos rem. +
      +
    • Modi pariatur quod totam. Deserunt doloribus eveniet, expedita.
    • +
    • Ad beatae dicta et fugit libero optio quaerat rem repellendus./
    • +
    • Architecto atque consequuntur corporis id iste magni.
    • +
    +
  4. +
  5. + Deserunt non placeat unde veniam veritatis? Odio quod. +
      +
    • Inventore iure magni quod repellendus tempora. Magnam neque, quia. Adipisci amet.
    • +
    • Consectetur adipisicing elit.
    • +
    • labque eum expedita illo inventore iusto laboriosam nesciunt non, odio provident.
    • +
    +
  6. +
+

+ A aliquam architecto consequatur labque dicta doloremque <li> doloribus, ducimus earum, est <p> + eveniet explicabo fuga fugit ipsum minima minus molestias nihil nisi non qui sunt vel voluptatibus? A dolorum illum nihil quidem. +

+
    +
  • +

    + Laboriosam nesciunt obcaecati optio qui. +

    +

    + Doloremque magni molestias reprehenderit. +

    +
      +
    • Accusamus aperiam blanditiis <p> commodi
    • +
    • Dolorum ea explicabo fugiat in ipsum
    • +
    +
  • +
  • +

    + Commodi dolor dolorem dolores eum expedita libero. +

    +

    + Accusamus alias consectetur dolores et, excepturi fuga iusto possimus. +

    +
      +
    • +

      + Accusantium ad alias atque aut autem consequuntur deserunt dignissimos eaque iure <p> maxime. +

      +

      + Dolorum in nisi numquam omnis quam sapiente sit vero. +

      +
    • +
    • +

      + Adipisci lab in nisi odit soluta sunt vitae commodi excepturi. +

      +
    • +
    +
  • +
  • +

    + Assumenda deserunt distinctio dolor iste mollitia nihil non? +

    +
  • +
+

+ Consectetur adipisicing elit dicta dolor iste. +

+

+ Consectetur ea natus officia omnis reprehenderit. +

+

+ Distinctio impedit quaerat sed! Accusamus + aliquam aspernatur enim expedita explicabo + . Libero molestiae + odio quasi unde ut? Ab exercitationem id numquam odio quisquam! +

+

+ Explicabo facilis nemo quidem natus tempore: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
WrestlerOriginFinisher
Bret “The Hitman” HartCalgary, ABSharpshooter
Stone Cold Steve AustinAustin, TXStone Cold Stunner
Randy SavageSarasota, FLElbow Drop
VaderBoulder, COVader Bomb
Razor RamonChuluota, FLRazor’s Edge
+

+ A aliquid autem lab doloremque, ea earum eum fuga fugit illo ipsa minus natus nisi <span> obcaecati pariatur + perferendis pofro suscipit tempore. +

+

+ Ad alias atque culpa illum earum optio +

+

+ Architecto consequatur eveniet illo in iure laborum minus omnis quibusdam sequi temporibus? Ab aliquid “atque dolores molestiae + nemo perferendis” reprehenderit saepe. +

+

+ Accusantium aliquid eligendi est fuga natus, quos vel? Adipisci aperiam asperiores aspernatur consectetur cupiditate + @distinctio/doloribus + et exercitationem expedita, facere facilis illum, impedit inventore + ipsa iure iusto magnam, magni minus nesciunt non officia possimus quod reiciendis. +

+

+ Cupiditate explicabo hic maiores +

+

+ Aliquam amet consequuntur distinctio ea est excepturi facere illum maiores nisi nobis non odit officiis + quisquam, similique tempora temporibus, tenetur ullam voluptates adipisci aperiam deleniti doloremque + ducimus eos. +

+

+ Ducimus qui quo tempora. lab enim explicabo hic inventore qui soluta voluptates voluptatum? Asperiores consectetur + delectus dolorem fugiat ipsa pariatur, quas quos repellendus repudiandae sunt aut blanditiis. +

+

+ Asperiores aspernatur autem error praesentium quidem. +

+

+ Ad blanditiis commodi, doloribus id iste repudiandae vero vitae. +

+

+ Atque consectetur lab debitis enim est et, facere fugit impedit, possimus quaerat quibusdam. +

+

+ Dolorem nihil placeat quibusdam veniam? Amet architecto at consequatur eligendi eveniet excepturi hic illo impedit in iste magni maxime + modi nisi nulla odio placeat quidem, quos rem repellat similique suscipit voluptate voluptates nobis omnis quo repellendus. +

+

+ Assumenda, eum, minima! Autem consectetur fugiat iste sit! Nobis omnis quo repellendus. +

+`; +export const demoCourseSteps = [ + { + order: 0, + title: 'Introduction', + subtitle: 'Introducing the library and how it works', + content: `

Introduction

${demoCourseContent}`, + }, + { + order: 1, + title: 'Get the sample code', + subtitle: 'Where to find the sample code and how to access it', + content: `

Get the sample code

${demoCourseContent}`, + }, + { + order: 2, + title: 'Create a Firebase project and Set up your app', + subtitle: + 'How to create a basic Firebase project and how to run it locally', + content: `

Create a Firebase project and Set up your app

${demoCourseContent}`, + }, + { + order: 3, + title: 'Install the Firebase Command Line Interface', + subtitle: 'Setting up the Firebase CLI to access command line tools', + content: `

Install the Firebase Command Line Interface

${demoCourseContent}`, + }, + { + order: 4, + title: 'Deploy and run the web app', + subtitle: 'How to build, push and run the project remotely', + content: `

Deploy and run the web app

${demoCourseContent}`, + }, + { + order: 5, + title: 'The Functions Directory', + subtitle: 'Introducing the Functions and Functions Directory', + content: `

The Functions Directory

${demoCourseContent}`, + }, + { + order: 6, + title: 'Import the Cloud Functions and Firebase Admin modules', + subtitle: + 'Create your first Function and run it to administer your app', + content: `

Import the Cloud Functions and Firebase Admin modules

${demoCourseContent}`, + }, + { + order: 7, + title: 'Welcome New Users', + subtitle: 'How to create a welcome message for the new users', + content: `

Welcome New Users

${demoCourseContent}`, + }, + { + order: 8, + title: 'Images moderation', + subtitle: 'How to moderate images; crop, resize, optimize', + content: `

Images moderation

${demoCourseContent}`, + }, + { + order: 9, + title: 'New Message Notifications', + subtitle: 'How to create and push a notification to a user', + content: `

New Message Notifications

${demoCourseContent}`, + }, + { + order: 10, + title: 'Congratulations!', + subtitle: 'Nice work, you have created your first application', + content: `

Congratulations!

${demoCourseContent}`, + }, +]; diff --git a/frontend/src/app/mock-api/apps/chat/api.ts b/frontend/src/app/mock-api/apps/chat/api.ts new file mode 100644 index 00000000..25b152ef --- /dev/null +++ b/frontend/src/app/mock-api/apps/chat/api.ts @@ -0,0 +1,160 @@ +import { Injectable } from '@angular/core'; +import { FuseMockApiService } from '@fuse/lib/mock-api'; +import { + chats as chatsData, + contacts as contactsData, + messages as messagesData, + profile as profileData, +} from 'app/mock-api/apps/chat/data'; +import { assign, cloneDeep, omit } from 'lodash-es'; + +@Injectable({ providedIn: 'root' }) +export class ChatMockApi { + private _chats: any[] = chatsData; + private _contacts: any[] = contactsData; + private _messages: any[] = messagesData; + private _profile: any = profileData; + + /** + * Constructor + */ + constructor(private _fuseMockApiService: FuseMockApiService) { + // Register Mock API handlers + this.registerHandlers(); + + // Modify the chats array to attach certain data to it + this._chats = this._chats.map((chat) => ({ + ...chat, + // Get the actual contact object from the id and attach it to the chat + contact: this._contacts.find( + (contact) => contact.id === chat.contactId + ), + // Since we use same set of messages on all chats, we assign them here. + messages: this._messages.map((message) => ({ + ...message, + chatId: chat.id, + contactId: + message.contactId === 'me' + ? this._profile.id + : chat.contactId, + isMine: message.contactId === 'me', + })), + })); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Register Mock API handlers + */ + registerHandlers(): void { + // ----------------------------------------------------------------------------------------------------- + // @ Chats - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService.onGet('api/apps/chat/chats').reply(() => { + // Clone the chats + const chats = cloneDeep(this._chats); + + // Return the response + return [200, chats]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Chat - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onGet('api/apps/chat/chat') + .reply(({ request }) => { + // Get the chat id + const id = request.params.get('id'); + + // Clone the chats + const chats = cloneDeep(this._chats); + + // Find the chat we need + const chat = chats.find((item) => item.id === id); + + // Return the response + return [200, chat]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Chat - PATCH + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onPatch('api/apps/chat/chat') + .reply(({ request }) => { + // Get the id and chat + const id = request.body.id; + const chat = cloneDeep(request.body.chat); + + // Prepare the updated chat + let updatedChat = null; + + // Find the chat and update it + this._chats.forEach((item, index, chats) => { + if (item.id === id) { + // Update the chat + chats[index] = assign({}, chats[index], chat); + + // Store the updated chat + updatedChat = chats[index]; + } + }); + + // Return the response + return [200, updatedChat]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Contacts - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService.onGet('api/apps/chat/contacts').reply(() => { + // Clone the contacts + let contacts = cloneDeep(this._contacts); + + // Sort the contacts by the name field by default + contacts.sort((a, b) => a.name.localeCompare(b.name)); + + // Omit details and attachments from contacts + contacts = contacts.map((contact) => + omit(contact, ['details', 'attachments']) + ); + + // Return the response + return [200, contacts]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Contact Details - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onGet('api/apps/chat/contact') + .reply(({ request }) => { + // Get the contact id + const id = request.params.get('id'); + + // Clone the contacts + const contacts = cloneDeep(this._contacts); + + // Find the contact + const contact = contacts.find((item) => item.id === id); + + // Return the response + return [200, contact]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Profile - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService.onGet('api/apps/chat/profile').reply(() => { + // Clone the profile + const profile = cloneDeep(this._profile); + + // Return the response + return [200, profile]; + }); + } +} diff --git a/frontend/src/app/mock-api/apps/chat/data.ts b/frontend/src/app/mock-api/apps/chat/data.ts new file mode 100644 index 00000000..6898eb75 --- /dev/null +++ b/frontend/src/app/mock-api/apps/chat/data.ts @@ -0,0 +1,3156 @@ +/* eslint-disable */ +import { DateTime } from 'luxon'; + +/* Get the current instant */ +const now = DateTime.now(); + +/** + * Attachments are common and will be filled from here + * to keep the demo data maintainable. + */ +const _attachments = { + media: [ + 'images/cards/01-320x200.jpg', + 'images/cards/02-320x200.jpg', + 'images/cards/03-320x200.jpg', + 'images/cards/04-320x200.jpg', + 'images/cards/05-320x200.jpg', + 'images/cards/06-320x200.jpg', + 'images/cards/07-320x200.jpg', + 'images/cards/08-320x200.jpg', + ], + docs: [], + links: [], +}; + +/** + * If a message belongs to our user, it's marked by setting it as + * 'me'. If it belongs to the user we are chatting with, then it + * left empty. We will be using this same conversation for each chat + * to keep things more maintainable for the demo. + */ +export const messages = [ + { + id: 'e6b2b82f-b199-4a60-9696-5f3e40d2715d', + chatId: '', + contactId: 'me', + value: 'Hi!', + createdAt: now + .minus({ week: 1 }) + .set({ + hour: 18, + minute: 56, + }) + .toISO(), + }, + { + id: 'eb82cf4b-fa93-4bf4-a88a-99e987ddb7ea', + chatId: '', + contactId: '', + value: 'Hey, dude!', + createdAt: now + .minus({ week: 1 }) + .set({ + hour: 19, + minute: 4, + }) + .toISO(), + }, + { + id: '3cf9b2a6-ae54-47db-97b2-ee139a8f84e5', + chatId: '', + contactId: '', + value: 'Long time no see.', + createdAt: now + .minus({ week: 1 }) + .set({ + hour: 19, + minute: 4, + }) + .toISO(), + }, + { + id: '2ab91b0f-fafb-45f3-88df-7efaff29134b', + chatId: '', + contactId: 'me', + value: 'Yeah, man... Things were quite busy for me and my family.', + createdAt: now + .minus({ week: 1 }) + .set({ + hour: 19, + minute: 6, + }) + .toISO(), + }, + { + id: '10e81481-378f-49ac-b06b-7c59dcc639ae', + chatId: '', + contactId: '', + value: "What's up? Anything I can help with?", + createdAt: now + .minus({ week: 1 }) + .set({ + hour: 19, + minute: 6, + }) + .toISO(), + }, + { + id: '3b334e72-6605-4ebd-a4f6-3850067048de', + chatId: '', + contactId: 'me', + value: "We've been on the move, changed 3 places over 4 months", + createdAt: now + .minus({ week: 1 }) + .set({ + hour: 19, + minute: 7, + }) + .toISO(), + }, + { + id: '25998113-3a96-4dd0-a7b9-4d2bb58db3f3', + chatId: '', + contactId: '', + value: "Wow! That's crazy! 🤯 What happened?", + createdAt: now + .minus({ week: 1 }) + .set({ + hour: 19, + minute: 7, + }) + .toISO(), + }, + { + id: '30adb3da-0e4f-487e-aec2-6d9f31e097f6', + chatId: '', + contactId: 'me', + value: 'You know I got a job in that big software company. First move was because of that.', + createdAt: now + .minus({ week: 1 }) + .set({ + hour: 19, + minute: 8, + }) + .toISO(), + }, + { + id: 'c0d6fd6e-d294-4845-8751-e84b8f2c4d3b', + chatId: '', + contactId: 'me', + value: 'Then they decided to re-locate me after a month', + createdAt: now + .minus({ week: 1 }) + .set({ + hour: 19, + minute: 8, + }) + .toISO(), + }, + { + id: '8d3c442b-62fa-496f-bffa-210ff5c1866b', + chatId: '', + contactId: 'me', + value: 'Which was an absolute pain because we just set up everything, house, kids school and all that.', + createdAt: now + .minus({ week: 1 }) + .set({ + hour: 19, + minute: 8, + }) + .toISO(), + }, + { + id: '3cf26ef0-e81f-4698-ac39-487454413332', + chatId: '', + contactId: 'me', + value: 'So we moved the second time.', + createdAt: now + .minus({ week: 1 }) + .set({ + hour: 19, + minute: 9, + }) + .toISO(), + }, + { + id: '415151b9-9ee9-40a4-a4ad-2d88146bc71b', + chatId: '', + contactId: '', + value: "It's crazy!", + createdAt: now + .minus({ week: 1 }) + .set({ + hour: 19, + minute: 9, + }) + .toISO(), + }, + { + id: 'd6f29648-c85c-4dfb-a6ff-6b7ebc40c993', + chatId: '', + contactId: 'me', + value: 'Then this virus thing happened and just after a week we moved in, they decided the whole department will be working remotely.', + createdAt: now + .minus({ week: 1 }) + .set({ + hour: 19, + minute: 10, + }) + .toISO(), + }, + { + id: '5329c20d-6754-47ec-af8c-660c72be3528', + chatId: '', + contactId: 'me', + value: "And then we decided to move back our first location because, you know, everything was already setup so that's the third time.", + createdAt: now + .minus({ week: 1 }) + .set({ + hour: 19, + minute: 10, + }) + .toISO(), + }, + { + id: '26f2ccbf-aef7-4b49-88df-f6b59381110a', + chatId: '', + contactId: '', + value: "Ohh dude, I'm really sorry you had to go through all that in such a short period of time", + createdAt: now + .minus({ week: 1 }) + .set({ + hour: 19, + minute: 11, + }) + .toISO(), + }, + { + id: 'ea7662d5-7b72-4c19-ad6c-f80320541001', + chatId: '', + contactId: '', + value: '😕', + createdAt: now + .minus({ week: 1 }) + .set({ + hour: 19, + minute: 11, + }) + .toISO(), + }, + { + id: '3a2d3a0e-839b-46e7-86ae-ca0826ecda7c', + chatId: '', + contactId: 'me', + value: 'Thanks, man! It was good catching up with you.', + createdAt: now + .minus({ week: 1 }) + .set({ + hour: 19, + minute: 11, + }) + .toISO(), + }, + { + id: '562e3524-15b7-464a-bbf6-9b2582e5e0ee', + chatId: '', + contactId: '', + value: 'Yeah dude. Hit me again next week so we can grab a coffee, remotely!', + createdAt: now + .minus({ week: 1 }) + .set({ + hour: 19, + minute: 12, + }) + .toISO(), + }, + { + id: '9269c775-bad5-46e1-b33b-2de8704ec1d6', + chatId: '', + contactId: 'me', + value: ':) Sure, man! See you next week!', + createdAt: now + .minus({ week: 1 }) + .set({ + hour: 19, + minute: 12, + }) + .toISO(), + }, + { + id: '779a27f2-bece-41c6-b9ca-c422570aee68', + chatId: '', + contactId: '', + value: 'See you later!', + createdAt: now + .minus({ week: 1 }) + .set({ + hour: 19, + minute: 12, + }) + .toISO(), + }, + { + id: 'bab8ca0e-b8e5-4375-807b-1c91fca25a5d', + chatId: '', + contactId: 'me', + value: 'Hey! Are you available right now? How about if we grab that coffee today? Remotely, of course :)', + createdAt: now + .set({ + hour: 12, + minute: 45, + }) + .toISO(), + }, + { + id: '8445a84d-599d-4e2d-a31c-5f4f29ad2b4c', + chatId: '', + contactId: '', + value: 'Hi!', + createdAt: now + .set({ + hour: 12, + minute: 56, + }) + .toISO(), + }, + { + id: '9f506742-50da-4350-af9d-61e53392fa08', + chatId: '', + contactId: '', + value: "Sure thing! I'm gonna call you in 5, is it okay?", + createdAt: now + .set({ + hour: 12, + minute: 56, + }) + .toISO(), + }, + { + id: 'ca8523d8-faed-45f7-af09-f6bd5c3f3875', + chatId: '', + contactId: 'me', + value: 'Awesome! Call me in 5 minutes..', + createdAt: now + .set({ + hour: 12, + minute: 58, + }) + .toISO(), + }, + { + id: '39944b00-1ffe-4ffb-8ca6-13c292812e06', + chatId: '', + contactId: '', + value: '👍🏻', + createdAt: now + .set({ + hour: 13, + minute: 0, + }) + .toISO(), + }, +]; +export const chats = [ + { + id: 'ff6bc7f1-449a-4419-af62-b89ce6cae0aa', + contactId: '9d3f0e7f-dcbd-4e56-a5e8-87b8154e9edf', + unreadCount: 2, + muted: false, + lastMessage: 'See you tomorrow!', + lastMessageAt: '26/04/2021', + }, + { + id: '4459a3f0-b65e-4df2-8c37-6ec72fcc4b31', + contactId: '16b9e696-ea95-4dd8-86c4-3caf705a1dc6', + unreadCount: 0, + muted: false, + lastMessage: 'See you tomorrow!', + lastMessageAt: '26/04/2021', + }, + { + id: 'f73a5a34-a723-4b35-8439-5289e0164c83', + contactId: 'bf172879-423a-4fd6-8df3-6d1938bbfe1f', + unreadCount: 1, + muted: false, + lastMessage: 'See you tomorrow!', + lastMessageAt: '26/04/2021', + }, + { + id: '747f101c-0371-4ca3-9f20-cb913a80fe89', + contactId: 'abd9e78b-9e96-428f-b3ff-4d934c401bee', + unreadCount: 0, + muted: true, + lastMessage: 'See you tomorrow!', + lastMessageAt: '26/04/2021', + }, + { + id: 'b3facfc4-dfc2-4ac2-b55d-cb70b3e68419', + contactId: '6519600a-5eaa-45f8-8bed-c46fddb3b26a', + unreadCount: 0, + muted: false, + lastMessage: 'See you tomorrow!', + lastMessageAt: '26/04/2021', + }, + { + id: 'e3127982-9e53-4611-ac27-eb70c84be4aa', + contactId: 'b62359fd-f2a8-46e6-904e-31052d1cd675', + unreadCount: 0, + muted: false, + lastMessage: 'See you tomorrow!', + lastMessageAt: '26/04/2021', + }, + { + id: 'a30351f3-bfa6-4ce3-b13a-82748fe0edee', + contactId: '2c37ed00-427a-46d7-8f8f-d711c768d1ee', + unreadCount: 0, + muted: false, + lastMessage: 'See you tomorrow!', + lastMessageAt: '26/04/2021', + }, + { + id: '5636c0ba-fa47-42ca-9160-27340583041e', + contactId: 'b8258ccf-48b5-46a2-9c95-e0bd7580c645', + unreadCount: 0, + muted: false, + lastMessage: 'See you tomorrow!', + lastMessageAt: '26/04/2021', + }, + { + id: 'feddd91a-51af-48d8-99b0-cd99ee060a36', + contactId: 'e2946946-b4b5-4fd7-bab4-62c38cdff2f1', + unreadCount: 0, + muted: false, + lastMessage: 'See you tomorrow!', + lastMessageAt: '26/04/2021', + }, + { + id: '89421c2f-1751-4040-b09b-4a4268db47b9', + contactId: '12148fa2-e0a4-49fb-b3c5-daeecdb5180a', + unreadCount: 0, + muted: true, + lastMessage: 'See you tomorrow!', + lastMessageAt: '26/04/2021', + }, + { + id: 'ffbbfdb4-0485-44aa-8521-5ce1eda3fd2f', + contactId: '81fdc48c-5572-4123-8a73-71b7892120de', + muted: false, + lastMessage: 'See you tomorrow!', + lastMessageAt: '26/04/2021', + }, + { + id: 'a477baea-df90-4e2f-b108-7791bcd50bc8', + contactId: 'a9a9f382-e4c3-42fb-9fe9-65aa534732b5', + unreadCount: 0, + muted: false, + lastMessage: 'See you tomorrow!', + lastMessageAt: '26/04/2021', + }, + { + id: '450840c8-aa0b-47a4-b6ca-b864ad9a3a88', + contactId: '7e8e1f1e-d19f-45c7-86bd-6fef599dae71', + unreadCount: 0, + muted: false, + lastMessage: 'See you tomorrow!', + lastMessageAt: '26/04/2021', + }, + { + id: '427270f0-841c-47f9-912c-3fd8139db5e6', + contactId: '8141dd08-3a6e-4770-912c-59d0ed06dde6', + unreadCount: 0, + muted: false, + lastMessage: 'See you tomorrow!', + lastMessageAt: '26/04/2021', + }, + { + id: '491b2918-e71e-4017-919e-0ba009afd003', + contactId: '114642a2-ccb7-4cb1-ad2b-5e9b6a0c1d2e', + unreadCount: 0, + muted: false, + lastMessage: 'See you tomorrow!', + lastMessageAt: '26/04/2021', + }, +]; +export const contacts = [ + { + id: 'cd5fa417-b667-482d-b208-798d9da3213c', + avatar: 'images/avatars/male-01.jpg', + name: 'Dejesus Michael', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'dejesusmichael@mail.org', + label: 'Personal', + }, + { + email: 'michael.dejesus@vitricomp.io', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'bs', + phoneNumber: '984 531 2468', + label: 'Mobile', + }, + { + country: 'bs', + phoneNumber: '806 470 2693', + label: 'Work', + }, + ], + title: 'Track Service Worker', + company: 'Vitricomp', + birthday: '1975-01-10T12:00:00.000Z', + address: '279 Independence Avenue, Calvary, Guam, PO4127', + }, + attachments: _attachments, + }, + { + id: 'beec5287-ed50-4504-858a-5dc3f8ce6935', + avatar: null, + name: 'Dena Molina', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'denamolina@mail.us', + label: 'Personal', + }, + { + email: 'molina.dena@envire.tv', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'io', + phoneNumber: '934 537 3180', + label: 'Mobile', + }, + ], + title: 'Weather Analyst', + company: 'Envire', + birthday: '1994-12-05T12:00:00.000Z', + address: '856 Woodside Avenue, Alfarata, Iowa, PO4992', + }, + attachments: _attachments, + }, + { + id: '9d3f0e7f-dcbd-4e56-a5e8-87b8154e9edf', + avatar: 'images/avatars/male-02.jpg', + name: 'Bernard Langley', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'bernardlangley@mail.com', + label: 'Personal', + }, + { + email: 'langley.bernard@boilcat.name', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'md', + phoneNumber: '893 548 2862', + label: 'Mobile', + }, + ], + title: 'Electromedical Equipment Technician', + company: 'Boilcat', + birthday: '1988-05-26T12:00:00.000Z', + address: '943 Adler Place, Hamilton, South Dakota, PO5592', + }, + attachments: _attachments, + }, + { + id: '42a5da95-5e6d-42fd-a09d-de755d123a47', + background: 'images/cards/16-640x480.jpg', + name: 'Mclaughlin Steele', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'mclaughlinsteele@mail.me', + label: 'Personal', + }, + { + email: 'steele.mclaughlin@accel.info', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'va', + phoneNumber: '830 484 3813', + label: 'Mobile', + }, + { + country: 'va', + phoneNumber: '999 475 2789', + label: 'Work', + }, + { + country: 'va', + phoneNumber: '933 406 3598', + label: 'Home', + }, + ], + company: 'Accel', + birthday: '1968-08-13T12:00:00.000Z', + address: '334 Sandford Street, Savage, Virgin Islands, PO1858', + }, + attachments: _attachments, + }, + { + id: 'a7806ced-03f1-4197-8b30-00bdd463366b', + avatar: 'images/avatars/male-04.jpg', + name: 'Marsh Cochran', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'marshcochran@mail.biz', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'tz', + phoneNumber: '864 401 3980', + label: 'Mobile', + }, + { + country: 'tz', + phoneNumber: '956 546 2589', + label: 'Work', + }, + ], + title: 'Fundraising Director', + company: 'Xsports', + birthday: '1983-12-22T12:00:00.000Z', + address: '487 Hamilton Walk, Bergoo, American Samoa, PO5616', + }, + attachments: _attachments, + }, + { + id: 'f4ad15d9-5a24-463a-88ea-6189d6bb3a53', + avatar: 'images/avatars/male-05.jpg', + name: 'Parrish Austin', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'parrishaustin@mail.co.uk', + label: 'Personal', + }, + { + email: 'austin.parrish@insource.net', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'lv', + phoneNumber: '834 426 3574', + label: 'Mobile', + }, + { + country: 'lv', + phoneNumber: '816 573 3694', + label: 'Work', + }, + { + country: 'lv', + phoneNumber: '967 515 2009', + label: 'Home', + }, + ], + title: 'Motor Winder', + company: 'Insource', + birthday: '1963-08-24T12:00:00.000Z', + address: '610 Harbor Lane, Cascades, Minnesota, PO8639', + }, + attachments: _attachments, + }, + { + id: '780d0111-5e5c-4694-8d1d-0ea421971fbf', + avatar: 'images/avatars/female-02.jpg', + name: 'Laverne Dodson', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'lavernedodson@mail.ca', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'ar', + phoneNumber: '964 417 2318', + label: 'Mobile', + }, + { + country: 'ar', + phoneNumber: '830 410 2506', + label: 'Work', + }, + ], + title: 'Television News Producer', + company: 'Lovepad', + birthday: '1973-09-25T12:00:00.000Z', + address: '428 Newport Street, Neahkahnie, Arkansas, PO8324', + }, + attachments: _attachments, + }, + { + id: 'bf172879-423a-4fd6-8df3-6d1938bbfe1f', + avatar: 'images/avatars/male-06.jpg', + name: 'Edwards Mckenzie', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'edwardsmckenzie@mail.org', + label: 'Personal', + }, + { + email: 'mckenzie.edwards@bugsall.io', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'pe', + phoneNumber: '934 519 2903', + label: 'Mobile', + }, + { + country: 'pe', + phoneNumber: '989 489 3662', + label: 'Work', + }, + { + country: 'pe', + phoneNumber: '813 461 2790', + label: 'Home', + }, + ], + title: 'Legal Assistant', + company: 'Bugsall', + birthday: '1988-07-27T12:00:00.000Z', + address: '384 Polhemus Place, Dalton, Palau, PO6038', + }, + attachments: _attachments, + }, + { + id: '1eaa3213-ece2-4ba6-8e15-eb36ca388f50', + avatar: 'images/avatars/female-03.jpg', + name: 'Trudy Berg', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'trudyberg@mail.us', + label: 'Personal', + }, + { + email: 'berg.trudy@satiance.tv', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'ls', + phoneNumber: '912 539 2770', + label: 'Mobile', + }, + ], + title: 'Meteorologist', + company: 'Satiance', + birthday: '1989-12-15T12:00:00.000Z', + address: '945 Jerome Avenue, Riceville, North Carolina, PO1625', + }, + attachments: _attachments, + }, + { + id: 'abd9e78b-9e96-428f-b3ff-4d934c401bee', + avatar: 'images/avatars/female-04.jpg', + name: 'Elsie Melendez', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'elsiemelendez@mail.com', + label: 'Personal', + }, + { + email: 'melendez.elsie@chillium.name', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'tg', + phoneNumber: '907 515 3007', + label: 'Mobile', + }, + { + country: 'tg', + phoneNumber: '967 534 2803', + label: 'Work', + }, + ], + title: 'Fundraising Director', + company: 'Chillium', + birthday: '1980-06-28T12:00:00.000Z', + address: '428 Varanda Place, Veyo, Oklahoma, PO6188', + }, + attachments: _attachments, + }, + { + id: 'efae92cc-3bd1-4c6a-a395-b6760c69bd55', + avatar: 'images/avatars/male-07.jpg', + name: 'Lamb Underwood', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'lambunderwood@mail.me', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'pf', + phoneNumber: '855 517 2767', + label: 'Mobile', + }, + { + country: 'pf', + phoneNumber: '906 442 3593', + label: 'Work', + }, + { + country: 'pf', + phoneNumber: '905 402 2121', + label: 'Home', + }, + ], + title: 'Legal Assistant', + company: 'Exotechno', + birthday: '1990-07-26T12:00:00.000Z', + address: '609 Greenpoint Avenue, Beason, Vermont, PO5229', + }, + attachments: _attachments, + }, + { + id: 'bde636a7-c3d2-4bff-939a-aab11df1516b', + avatar: null, + name: 'Tessa Valdez', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'tessavaldez@mail.info', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'dz', + phoneNumber: '892 430 2631', + label: 'Mobile', + }, + { + country: 'dz', + phoneNumber: '997 525 2354', + label: 'Work', + }, + { + country: 'dz', + phoneNumber: '907 472 2857', + label: 'Home', + }, + ], + title: 'Banker Mason', + company: 'Securia', + birthday: '1994-01-10T12:00:00.000Z', + address: '183 Crosby Avenue, Blanco, Mississippi, PO3463', + }, + attachments: _attachments, + }, + { + id: '6519600a-5eaa-45f8-8bed-c46fddb3b26a', + background: 'images/cards/24-640x480.jpg', + name: 'Mcleod Wagner', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'mcleodwagner@mail.biz', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'at', + phoneNumber: '977 590 2773', + label: 'Mobile', + }, + { + country: 'at', + phoneNumber: '828 496 3813', + label: 'Work', + }, + { + country: 'at', + phoneNumber: '831 432 2512', + label: 'Home', + }, + ], + company: 'Inrt', + birthday: '1980-12-03T12:00:00.000Z', + address: '736 Glen Street, Kaka, West Virginia, PO9350', + }, + attachments: _attachments, + }, + { + id: '6d80a6f6-2884-4ac4-9c73-06b82c220017', + avatar: 'images/avatars/female-06.jpg', + name: 'Kristie Hall', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'kristiehall@mail.co.uk', + label: 'Personal', + }, + { + email: 'hall.kristie@austech.net', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'tn', + phoneNumber: '841 530 3641', + label: 'Mobile', + }, + { + country: 'tn', + phoneNumber: '941 410 3743', + label: 'Work', + }, + { + country: 'tn', + phoneNumber: '938 599 3850', + label: 'Home', + }, + ], + title: 'Electromedical Equipment Technician', + company: 'Austech', + birthday: '1975-08-31T12:00:00.000Z', + address: '547 Revere Place, Hoehne, New Hampshire, PO2125', + }, + attachments: _attachments, + }, + { + id: '35190d23-036e-44ef-b545-cc744c626edd', + avatar: 'images/avatars/female-07.jpg', + name: 'Shannon Kennedy', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'shannonkennedy@mail.ca', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'gb', + phoneNumber: '899 508 2992', + label: 'Mobile', + }, + { + country: 'gb', + phoneNumber: '834 499 3354', + label: 'Work', + }, + { + country: 'gb', + phoneNumber: '834 526 3388', + label: 'Home', + }, + ], + title: 'Gas Meter Mechanic', + company: 'Eventix', + birthday: '1994-09-07T12:00:00.000Z', + address: '480 Chase Court, Edinburg, Kansas, PO5357', + }, + attachments: _attachments, + }, + { + id: 'b018c194-68ec-4915-ab56-e9f3bd2d98db', + avatar: 'images/avatars/female-08.jpg', + name: 'Martha Swanson', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'marthaswanson@mail.org', + label: 'Personal', + }, + { + email: 'swanson.martha@sequitur.io', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'gb', + phoneNumber: '844 480 3309', + label: 'Mobile', + }, + { + country: 'gb', + phoneNumber: '981 591 3239', + label: 'Work', + }, + { + country: 'gb', + phoneNumber: '923 484 3147', + label: 'Home', + }, + ], + title: 'Short Story Writer', + company: 'Sequitur', + birthday: '1993-12-31T12:00:00.000Z', + address: '595 Howard Place, Convent, Rhode Island, PO6993', + }, + attachments: _attachments, + }, + { + id: 'b7c355e9-e003-467e-82d2-4f6978c1a696', + avatar: 'images/avatars/female-09.jpg', + name: 'Jacklyn Morgan', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'jacklynmorgan@mail.us', + label: 'Personal', + }, + { + email: 'morgan.jacklyn@shopabout.tv', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'so', + phoneNumber: '974 542 2061', + label: 'Mobile', + }, + ], + title: 'Animal Sitter', + company: 'Shopabout', + birthday: '1976-09-30T12:00:00.000Z', + address: '971 Conover Street, Statenville, Louisiana, PO6622', + }, + attachments: _attachments, + }, + { + id: 'cfa07b7c-93d1-42e7-9592-493d9efc78ae', + avatar: 'images/avatars/female-10.jpg', + name: 'Tonya Bowers', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'tonyabowers@mail.com', + label: 'Personal', + }, + { + email: 'bowers.tonya@tourmania.name', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'tv', + phoneNumber: '922 585 2914', + label: 'Mobile', + }, + { + country: 'tv', + phoneNumber: '913 538 2961', + label: 'Work', + }, + ], + title: 'Track Service Worker', + company: 'Tourmania', + birthday: '1976-06-14T12:00:00.000Z', + address: '197 Marconi Place, Welda, Delaware, PO6061', + }, + attachments: _attachments, + }, + { + id: '00feeb63-c83a-4655-a37e-a07da10cfa1c', + avatar: 'images/avatars/female-11.jpg', + name: 'Latonya Cruz', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'latonyacruz@mail.me', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'tm', + phoneNumber: '981 508 2080', + label: 'Mobile', + }, + { + country: 'tm', + phoneNumber: '817 425 2052', + label: 'Work', + }, + { + country: 'tm', + phoneNumber: '939 434 3805', + label: 'Home', + }, + ], + title: 'Motor Winder', + company: 'Zilch', + birthday: '1967-11-28T12:00:00.000Z', + address: '775 Dahill Road, Iberia, California, PO2169', + }, + attachments: _attachments, + }, + { + id: '142abf21-e635-4a7d-9330-e57f66adcdbe', + avatar: 'images/avatars/female-12.jpg', + name: 'Evangelina Mcclain', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'evangelinamcclain@mail.info', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'ck', + phoneNumber: '992 583 3187', + label: 'Mobile', + }, + { + country: 'ck', + phoneNumber: '881 472 3297', + label: 'Work', + }, + { + country: 'ck', + phoneNumber: '846 477 3596', + label: 'Home', + }, + ], + title: 'Congressional Representative', + company: 'Straloy', + birthday: '1976-02-15T12:00:00.000Z', + address: '305 Columbia Street, Dupuyer, Puerto Rico, PO8744', + }, + attachments: _attachments, + }, + { + id: 'e4f255a3-b5dd-45a7-975f-c399604a399a', + avatar: 'images/avatars/male-09.jpg', + name: 'Herring Gonzales', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'herringgonzales@mail.biz', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'ai', + phoneNumber: '995 411 2513', + label: 'Mobile', + }, + { + country: 'ai', + phoneNumber: '839 492 2760', + label: 'Work', + }, + ], + title: 'Gas Meter Mechanic', + company: 'Cubix', + birthday: '1995-02-16T12:00:00.000Z', + address: '195 Brooklyn Road, Jeff, Marshall Islands, PO2943', + }, + attachments: _attachments, + }, + { + id: 'ab4f712d-d712-41a8-b567-be4c66c349a3', + avatar: 'images/avatars/female-13.jpg', + name: 'Alyce Cash', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'alycecash@mail.co.uk', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'ht', + phoneNumber: '969 499 3077', + label: 'Mobile', + }, + { + country: 'ht', + phoneNumber: '907 513 2784', + label: 'Work', + }, + ], + title: 'Weather Analyst', + company: 'Qnekt', + birthday: '1973-12-19T12:00:00.000Z', + address: '964 Henry Street, Eureka, Indiana, PO1035', + }, + attachments: _attachments, + }, + { + id: '5d067800-c301-46c6-a7f7-28dc89d9a554', + avatar: null, + name: 'Kristine Pacheco', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'kristinepacheco@mail.net', + label: 'Personal', + }, + { + email: 'pacheco.kristine@vurbo.ca', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'mm', + phoneNumber: '977 516 2492', + label: 'Mobile', + }, + ], + title: 'Short Story Writer', + company: 'Vurbo', + birthday: '1985-10-22T12:00:00.000Z', + address: '622 Dodworth Street, Rose, Arizona, PO9530', + }, + attachments: _attachments, + }, + { + id: 'c500255a-1173-47d0-a0e4-4944d48fc12a', + avatar: 'images/avatars/male-10.jpg', + name: 'English Haney', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'englishhaney@mail.org', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'lb', + phoneNumber: '989 567 3834', + label: 'Mobile', + }, + ], + title: 'Meteorologist', + company: 'Photobin', + birthday: '1969-09-05T12:00:00.000Z', + address: '579 Pooles Lane, Belleview, Montana, PO4106', + }, + attachments: _attachments, + }, + { + id: 'b62359fd-f2a8-46e6-904e-31052d1cd675', + avatar: 'images/avatars/male-11.jpg', + name: 'Joseph Strickland', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'josephstrickland@mail.io', + label: 'Personal', + }, + { + email: 'strickland.joseph@bytrex.us', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'jo', + phoneNumber: '990 450 2729', + label: 'Mobile', + }, + ], + title: 'Hotel Manager', + company: 'Bytrex', + birthday: '1991-09-08T12:00:00.000Z', + address: '844 Ellery Street, Hondah, Texas, PO1272', + }, + attachments: _attachments, + }, + { + id: '16b9e696-ea95-4dd8-86c4-3caf705a1dc6', + avatar: 'images/avatars/male-12.jpg', + name: 'Nunez Faulkner', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'nunezfaulkner@mail.tv', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'xk', + phoneNumber: '909 552 3327', + label: 'Mobile', + }, + ], + title: 'Hotel Manager', + company: 'Buzzopia', + birthday: '1982-01-23T12:00:00.000Z', + address: '614 Herkimer Court, Darrtown, Nebraska, PO9308', + }, + attachments: _attachments, + }, + { + id: '19662ecf-0686-4aad-a46c-24b552eb2ff5', + avatar: 'images/avatars/female-15.jpg', + name: 'Juana Morrow', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'juanamorrow@mail.com', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'ee', + phoneNumber: '868 438 3943', + label: 'Mobile', + }, + ], + title: 'Meteorologist', + company: 'Lyria', + birthday: '1992-03-29T12:00:00.000Z', + address: '663 Drew Street, Juntura, Georgia, PO9857', + }, + attachments: _attachments, + }, + { + id: '26dfe954-8bf3-45ee-b285-1d0a88c8d3ea', + avatar: 'images/avatars/male-13.jpg', + name: 'Lara Gaines', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'laragaines@mail.name', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'mr', + phoneNumber: '891 498 2043', + label: 'Mobile', + }, + ], + title: 'Electromedical Equipment Technician', + company: 'Acruex', + birthday: '1961-06-07T12:00:00.000Z', + address: '762 Troutman Street, Drummond, Oregon, PO6973', + }, + attachments: _attachments, + }, + { + id: 'd6462af2-c488-4de7-9b26-3845bd2983f9', + avatar: 'images/avatars/male-14.jpg', + name: 'Johnston Riddle', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'johnstonriddle@mail.me', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'bt', + phoneNumber: '979 541 2691', + label: 'Mobile', + }, + { + country: 'bt', + phoneNumber: '909 407 3887', + label: 'Work', + }, + { + country: 'bt', + phoneNumber: '864 557 3128', + label: 'Home', + }, + ], + title: 'Hotel Manager', + company: 'Xleen', + birthday: '1972-09-13T12:00:00.000Z', + address: + '674 Bryant Street, Grahamtown, Federated States Of Micronesia, PO2757', + }, + attachments: _attachments, + }, + { + id: 'a1723c04-69fe-4573-a135-6645658afe76', + avatar: null, + name: 'Vargas Gardner', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'vargasgardner@mail.info', + label: 'Personal', + }, + { + email: 'gardner.vargas@cosmosis.biz', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'bi', + phoneNumber: '855 456 2754', + label: 'Mobile', + }, + ], + title: 'Bindery Machine Operator', + company: 'Cosmosis', + birthday: '1979-10-21T12:00:00.000Z', + address: '869 Seton Place, Chemung, Maine, PO8109', + }, + attachments: _attachments, + }, + { + id: '823e6166-c0c8-4373-9270-8a0d17489a08', + avatar: 'images/avatars/male-16.jpg', + name: 'Mccall Day', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'mccallday@mail.co.uk', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'se', + phoneNumber: '993 504 3286', + label: 'Mobile', + }, + { + country: 'se', + phoneNumber: '924 434 2238', + label: 'Work', + }, + { + country: 'se', + phoneNumber: '816 466 2634', + label: 'Home', + }, + ], + title: 'Historiographer', + company: 'Nipaz', + birthday: '1964-03-05T12:00:00.000Z', + address: '854 Hanover Place, Harleigh, New Jersey, PO9459', + }, + attachments: _attachments, + }, + { + id: '2c37ed00-427a-46d7-8f8f-d711c768d1ee', + avatar: 'images/avatars/male-17.jpg', + name: 'Silva Foster', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'silvafoster@mail.net', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'bn', + phoneNumber: '916 511 3837', + label: 'Mobile', + }, + { + country: 'bn', + phoneNumber: '949 564 3247', + label: 'Work', + }, + ], + title: 'Insurance Analyst', + company: 'Extrawear', + birthday: '1980-04-29T12:00:00.000Z', + address: '137 Bridge Street, Sisquoc, District Of Columbia, PO4105', + }, + attachments: _attachments, + }, + { + id: '944764c0-b261-4428-9188-bbd3022d66a8', + avatar: 'images/avatars/female-16.jpg', + name: 'Cathryn Snider', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'cathrynsnider@mail.ca', + label: 'Personal', + }, + { + email: 'snider.cathryn@phormula.org', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'na', + phoneNumber: '896 471 3036', + label: 'Mobile', + }, + { + country: 'na', + phoneNumber: '851 491 3567', + label: 'Work', + }, + { + country: 'na', + phoneNumber: '805 487 2016', + label: 'Home', + }, + ], + title: 'Short Story Writer', + company: 'Phormula', + birthday: '1981-06-09T12:00:00.000Z', + address: '528 Glenmore Avenue, Elrama, Illinois, PO2952', + }, + attachments: _attachments, + }, + { + id: 'f2b3c756-5ad2-4d4b-aee5-b32c91457128', + avatar: null, + name: 'Mooney Cantrell', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'mooneycantrell@mail.io', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'bh', + phoneNumber: '915 577 3020', + label: 'Mobile', + }, + { + country: 'bh', + phoneNumber: '923 431 3594', + label: 'Work', + }, + ], + title: 'Fundraising Director', + company: 'Crustatia', + birthday: '1968-12-07T12:00:00.000Z', + address: '277 Coventry Road, Fairforest, Nevada, PO6031', + }, + attachments: _attachments, + }, + { + id: '54b1c201-4b2b-4be0-ad70-a6413e9628cd', + avatar: 'images/avatars/female-17.jpg', + name: 'Saundra Murphy', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'saundramurphy@mail.us', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'mt', + phoneNumber: '902 529 2999', + label: 'Mobile', + }, + ], + title: 'Dental Laboratory Worker', + company: 'Zilencio', + birthday: '1983-11-07T12:00:00.000Z', + address: '557 Monroe Street, Mayfair, Maryland, PO7200', + }, + attachments: _attachments, + }, + { + id: 'faf979c7-a13b-445a-b30a-08845f5fa90e', + avatar: 'images/avatars/female-18.jpg', + name: 'Enid Sparks', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'enidsparks@mail.tv', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'bh', + phoneNumber: '813 410 3258', + label: 'Mobile', + }, + { + country: 'bh', + phoneNumber: '877 501 2767', + label: 'Work', + }, + ], + title: 'Historiographer', + company: 'Skybold', + birthday: '1984-05-04T12:00:00.000Z', + address: '219 Village Court, Keyport, Alabama, PO7776', + }, + attachments: _attachments, + }, + { + id: '2bfa2be5-7688-48d5-b5ac-dc0d9ac97f14', + avatar: null, + name: 'Nadia Mcknight', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'nadiamcknight@mail.com', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'tk', + phoneNumber: '943 511 2203', + label: 'Mobile', + }, + { + country: 'tk', + phoneNumber: '817 578 2993', + label: 'Work', + }, + ], + title: 'Legal Assistant', + company: 'Pearlesex', + birthday: '1973-10-06T12:00:00.000Z', + address: '448 Berriman Street, Reinerton, Washington, PO6704', + }, + attachments: _attachments, + }, + { + id: '77a4383b-b5a5-4943-bc46-04c3431d1566', + avatar: 'images/avatars/male-19.jpg', + name: 'Best Blackburn', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'bestblackburn@mail.name', + label: 'Personal', + }, + { + email: 'blackburn.best@beadzza.me', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'gl', + phoneNumber: '814 498 3701', + label: 'Mobile', + }, + ], + title: 'Hotel Manager', + company: 'Beadzza', + birthday: '1987-06-07T12:00:00.000Z', + address: '578 Tampa Court, Wescosville, Ohio, PO4108', + }, + attachments: _attachments, + }, + { + id: '8bb0f597-673a-47ca-8c77-2f83219cb9af', + avatar: null, + name: 'Duncan Carver', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'duncancarver@mail.info', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'jm', + phoneNumber: '968 547 2111', + label: 'Mobile', + }, + { + country: 'jm', + phoneNumber: '968 433 3120', + label: 'Work', + }, + { + country: 'jm', + phoneNumber: '905 425 2777', + label: 'Home', + }, + ], + title: 'Historiographer', + company: 'Hotcakes', + birthday: '1980-09-15T12:00:00.000Z', + address: '931 Bristol Street, Why, South Carolina, PO9700', + }, + attachments: _attachments, + }, + { + id: 'c318e31f-1d74-49c5-8dae-2bc5805e2fdb', + avatar: 'images/avatars/male-01.jpg', + name: 'Martin Richards', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'martinrichards@mail.biz', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'mg', + phoneNumber: '902 500 2668', + label: 'Mobile', + }, + { + country: 'mg', + phoneNumber: '947 559 2919', + label: 'Work', + }, + { + country: 'mg', + phoneNumber: '934 434 3768', + label: 'Home', + }, + ], + title: 'Dental Laboratory Worker', + company: 'Overfork', + birthday: '1977-04-12T12:00:00.000Z', + address: '268 Hutchinson Court, Drytown, Florida, PO3041', + }, + attachments: _attachments, + }, + { + id: '0a8bc517-631a-4a93-aacc-000fa2e8294c', + avatar: 'images/avatars/female-20.jpg', + name: 'Candice Munoz', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'candicemunoz@mail.co.uk', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'fm', + phoneNumber: '838 562 2769', + label: 'Mobile', + }, + ], + title: 'Legal Assistant', + company: 'Eclipto', + birthday: '1976-09-09T12:00:00.000Z', + address: '946 Remsen Street, Caroline, New Mexico, PO3247', + }, + attachments: _attachments, + }, + { + id: 'a4c9945a-757b-40b0-8942-d20e0543cabd', + avatar: 'images/avatars/female-01.jpg', + name: 'Vickie Mosley', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'vickiemosley@mail.net', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'tr', + phoneNumber: '939 555 3054', + label: 'Mobile', + }, + { + country: 'tr', + phoneNumber: '852 486 2053', + label: 'Work', + }, + ], + title: 'Bindery Machine Operator', + company: 'Strozen', + birthday: '1989-06-21T12:00:00.000Z', + address: '397 Vandalia Avenue, Rockingham, Michigan, PO8089', + }, + attachments: _attachments, + }, + { + id: 'b8258ccf-48b5-46a2-9c95-e0bd7580c645', + avatar: 'images/avatars/female-02.jpg', + name: 'Tina Harris', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'tinaharris@mail.ca', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'gp', + phoneNumber: '933 464 2431', + label: 'Mobile', + }, + { + country: 'gp', + phoneNumber: '894 535 3609', + label: 'Work', + }, + ], + title: 'Short Story Writer', + company: 'Gallaxia', + birthday: '1976-09-10T12:00:00.000Z', + address: '821 Beverly Road, Tyro, Colorado, PO4248', + }, + attachments: _attachments, + }, + { + id: 'f004ea79-98fc-436c-9ba5-6cfe32fe583d', + avatar: 'images/avatars/male-02.jpg', + name: 'Holt Manning', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'holtmanning@mail.org', + label: 'Personal', + }, + { + email: 'manning.holt@idetica.io', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'nz', + phoneNumber: '822 531 2600', + label: 'Mobile', + }, + { + country: 'nz', + phoneNumber: '922 549 2094', + label: 'Work', + }, + ], + title: 'Fundraising Director', + company: 'Idetica', + birthday: '1973-11-08T12:00:00.000Z', + address: '364 Porter Avenue, Delshire, Missouri, PO8911', + }, + attachments: _attachments, + }, + { + id: '8b69fe2d-d7cc-4a3d-983d-559173e37d37', + background: 'images/cards/28-640x480.jpg', + name: 'Misty Ramsey', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'mistyramsey@mail.us', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'kp', + phoneNumber: '990 457 2106', + label: 'Mobile', + }, + { + country: 'kp', + phoneNumber: '918 550 2946', + label: 'Work', + }, + ], + company: 'Grupoli', + birthday: '1969-08-10T12:00:00.000Z', + address: '101 Sackett Street, Naomi, Tennessee, PO6335', + }, + attachments: _attachments, + }, + { + id: 'cdcc62e4-1520-4ccc-803d-52868c7e01ba', + avatar: 'images/avatars/female-04.jpg', + name: 'Dee Alvarado', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'deealvarado@mail.tv', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'nu', + phoneNumber: '855 445 2483', + label: 'Mobile', + }, + { + country: 'nu', + phoneNumber: '858 415 2860', + label: 'Work', + }, + { + country: 'nu', + phoneNumber: '968 587 2752', + label: 'Home', + }, + ], + title: 'Dental Laboratory Worker', + company: 'Tsunamia', + birthday: '1996-06-17T12:00:00.000Z', + address: '956 Pierrepont Street, Crumpler, Hawaii, PO3299', + }, + attachments: _attachments, + }, + { + id: 'e2946946-b4b5-4fd7-bab4-62c38cdff2f1', + avatar: 'images/avatars/female-05.jpg', + name: 'Samantha Jacobson', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'samanthajacobson@mail.com', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'es', + phoneNumber: '879 591 3327', + label: 'Mobile', + }, + ], + title: 'Dental Laboratory Worker', + company: 'Emoltra', + birthday: '1972-02-04T12:00:00.000Z', + address: '384 Love Lane, Dyckesville, New York, PO4115', + }, + attachments: _attachments, + }, + { + id: 'fdc77706-6ba2-4397-b2f8-a9a0b6495153', + avatar: 'images/avatars/female-06.jpg', + name: 'Rhea Landry', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'rhealandry@mail.name', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'jp', + phoneNumber: '906 579 3698', + label: 'Mobile', + }, + { + country: 'jp', + phoneNumber: '841 475 2681', + label: 'Work', + }, + ], + title: 'Electromedical Equipment Technician', + company: 'Comtent', + birthday: '1988-05-22T12:00:00.000Z', + address: '725 Arlington Avenue, Mathews, Wyoming, PO4562', + }, + attachments: _attachments, + }, + { + id: '12148fa2-e0a4-49fb-b3c5-daeecdb5180a', + avatar: 'images/avatars/female-07.jpg', + name: 'Olga Rhodes', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'olgarhodes@mail.me', + label: 'Personal', + }, + { + email: 'rhodes.olga@moreganic.info', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'tl', + phoneNumber: '971 514 3366', + label: 'Mobile', + }, + { + country: 'tl', + phoneNumber: '807 480 2033', + label: 'Work', + }, + { + country: 'tl', + phoneNumber: '810 528 3783', + label: 'Home', + }, + ], + title: 'Pastry Baker', + company: 'Moreganic', + birthday: '1971-08-13T12:00:00.000Z', + address: '253 Beard Street, Staples, Massachusetts, PO8089', + }, + attachments: _attachments, + }, + { + id: '07dd64eb-8b8f-4765-a16c-8db083c45096', + avatar: 'images/avatars/female-08.jpg', + name: 'Lorraine Pennington', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'lorrainepennington@mail.biz', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'fm', + phoneNumber: '932 404 3308', + label: 'Mobile', + }, + { + country: 'fm', + phoneNumber: '979 550 3200', + label: 'Work', + }, + { + country: 'fm', + phoneNumber: '868 557 3568', + label: 'Home', + }, + ], + title: 'Electromedical Equipment Technician', + company: 'Marvane', + birthday: '1967-06-10T12:00:00.000Z', + address: '962 Whitney Avenue, Sussex, North Dakota, PO5796', + }, + attachments: _attachments, + }, + { + id: '81fdc48c-5572-4123-8a73-71b7892120de', + avatar: 'images/avatars/female-09.jpg', + name: 'Earlene Rosales', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'earlenerosales@mail.co.uk', + label: 'Personal', + }, + { + email: 'rosales.earlene@softmicro.net', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'ki', + phoneNumber: '927 589 3619', + label: 'Mobile', + }, + ], + title: 'Historiographer', + company: 'Softmicro', + birthday: '1960-11-13T12:00:00.000Z', + address: '981 Kingston Avenue, Topaz, Connecticut, PO6866', + }, + attachments: _attachments, + }, + { + id: 'f8bbf6be-d49a-41a3-bb80-3d51df84c12b', + avatar: 'images/avatars/female-10.jpg', + name: 'Marcia Hatfield', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'marciahatfield@mail.ca', + label: 'Personal', + }, + { + email: 'hatfield.marcia@datagen.org', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'no', + phoneNumber: '883 432 3718', + label: 'Mobile', + }, + { + country: 'no', + phoneNumber: '934 516 2135', + label: 'Work', + }, + { + country: 'no', + phoneNumber: '923 596 3843', + label: 'Home', + }, + ], + title: 'Track Service Worker', + company: 'Datagen', + birthday: '1980-02-26T12:00:00.000Z', + address: '802 Preston Court, Waikele, Pennsylvania, PO7421', + }, + attachments: _attachments, + }, + { + id: 'cd482941-3eaf-4560-ac37-56a9296025df', + avatar: 'images/avatars/female-11.jpg', + name: 'Liliana Ayala', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'lilianaayala@mail.io', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'bd', + phoneNumber: '936 590 2412', + label: 'Mobile', + }, + ], + title: 'Insurance Analyst', + company: 'Pharmex', + birthday: '1988-04-27T12:00:00.000Z', + address: '935 Guider Avenue, Kipp, Wisconsin, PO5282', + }, + attachments: _attachments, + }, + { + id: '22f18d47-ff8d-440e-888d-a1747c093052', + avatar: 'images/avatars/female-12.jpg', + name: 'Alice Harding', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'aliceharding@mail.us', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'sx', + phoneNumber: '881 472 3113', + label: 'Mobile', + }, + { + country: 'sx', + phoneNumber: '974 548 3124', + label: 'Work', + }, + { + country: 'sx', + phoneNumber: '800 518 3615', + label: 'Home', + }, + ], + title: 'Track Service Worker', + company: 'Futurity', + birthday: '1985-09-17T12:00:00.000Z', + address: '387 Holt Court, Thomasville, Alaska, PO2867', + }, + attachments: _attachments, + }, + { + id: 'a9a9f382-e4c3-42fb-9fe9-65aa534732b5', + avatar: 'images/avatars/female-13.jpg', + name: 'Francisca Perkins', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'franciscaperkins@mail.tv', + label: 'Personal', + }, + { + email: 'perkins.francisca@overplex.com', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'au', + phoneNumber: '830 430 3437', + label: 'Mobile', + }, + { + country: 'au', + phoneNumber: '868 538 2886', + label: 'Work', + }, + ], + title: 'Dental Laboratory Worker', + company: 'Overplex', + birthday: '1966-08-14T12:00:00.000Z', + address: '733 Delmonico Place, Belvoir, Virginia, PO7102', + }, + attachments: _attachments, + }, + { + id: '0222b24b-c288-48d1-b356-0f087fa172f8', + avatar: null, + name: 'Warren Gates', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'warrengates@mail.name', + label: 'Personal', + }, + { + email: 'gates.warren@qualitex.me', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'gt', + phoneNumber: '847 513 2248', + label: 'Mobile', + }, + { + country: 'gt', + phoneNumber: '866 591 3665', + label: 'Work', + }, + { + country: 'gt', + phoneNumber: '877 539 3840', + label: 'Home', + }, + ], + title: 'Banker Mason', + company: 'Qualitex', + birthday: '1977-02-23T12:00:00.000Z', + address: '713 Fane Court, Lemoyne, Kentucky, PO3601', + }, + attachments: _attachments, + }, + { + id: '0630f1ca-cdb9-405d-b134-68f733334089', + avatar: 'images/avatars/female-14.jpg', + name: 'Maryann Mcintyre', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'maryannmcintyre@mail.info', + label: 'Personal', + }, + { + email: 'mcintyre.maryann@aquafire.biz', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'bf', + phoneNumber: '861 419 2752', + label: 'Mobile', + }, + { + country: 'bf', + phoneNumber: '935 553 3031', + label: 'Work', + }, + ], + title: 'Fundraising Director', + company: 'Aquafire', + birthday: '1963-04-07T12:00:00.000Z', + address: '698 Brooklyn Avenue, Dixonville, Utah, PO2712', + }, + attachments: _attachments, + }, + { + id: '999c24f3-7bb8-4a01-85ca-2fca7863c57e', + avatar: 'images/avatars/female-15.jpg', + name: 'Sharon Marshall', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'sharonmarshall@mail.co.uk', + label: 'Personal', + }, + { + email: 'marshall.sharon@utara.net', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'fo', + phoneNumber: '947 441 2999', + label: 'Mobile', + }, + { + country: 'fo', + phoneNumber: '984 441 2615', + label: 'Work', + }, + { + country: 'fo', + phoneNumber: '824 541 2714', + label: 'Home', + }, + ], + title: 'Legal Assistant', + company: 'Utara', + birthday: '1960-01-26T12:00:00.000Z', + address: '923 Ivan Court, Hatteras, Idaho, PO7573', + }, + attachments: _attachments, + }, + { + id: '7e8e1f1e-d19f-45c7-86bd-6fef599dae71', + avatar: 'images/avatars/female-16.jpg', + name: 'Margo Witt', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'margowitt@mail.ca', + label: 'Personal', + }, + { + email: 'witt.margo@norsul.org', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'ao', + phoneNumber: '992 596 3391', + label: 'Mobile', + }, + { + country: 'ao', + phoneNumber: '950 489 2505', + label: 'Work', + }, + { + country: 'ao', + phoneNumber: '891 540 2231', + label: 'Home', + }, + ], + title: 'Television News Producer', + company: 'Norsul', + birthday: '1975-08-31T12:00:00.000Z', + address: '539 Rockaway Avenue, Whitmer, Guam, PO4871', + }, + attachments: _attachments, + }, + { + id: 'bedcb6a2-da83-4631-866a-77d10d239477', + avatar: 'images/avatars/male-04.jpg', + name: 'Alvarado Turner', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'alvaradoturner@mail.io', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'lv', + phoneNumber: '961 537 3956', + label: 'Mobile', + }, + ], + title: 'Fundraising Director', + company: 'Geologix', + birthday: '1985-12-08T12:00:00.000Z', + address: '233 Willmohr Street, Cressey, Iowa, PO1962', + }, + attachments: _attachments, + }, + { + id: '66f9de1b-f842-4d4c-bb59-f97e91db0462', + avatar: 'images/avatars/male-05.jpg', + name: 'Maldonado Rodriquez', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'maldonadorodriquez@mail.us', + label: 'Personal', + }, + { + email: 'rodriquez.maldonado@zentility.tv', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'et', + phoneNumber: '811 502 3398', + label: 'Mobile', + }, + { + country: 'et', + phoneNumber: '877 402 2443', + label: 'Work', + }, + { + country: 'et', + phoneNumber: '949 536 3451', + label: 'Home', + }, + ], + title: 'Dental Laboratory Worker', + company: 'Zentility', + birthday: '1993-06-01T12:00:00.000Z', + address: '916 Cobek Court, Morningside, South Dakota, PO2019', + }, + attachments: _attachments, + }, + { + id: '9cb0ea57-3461-4182-979b-593b0c1ec6c3', + avatar: 'images/avatars/male-06.jpg', + name: 'Tran Duke', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'tranduke@mail.com', + label: 'Personal', + }, + { + email: 'duke.tran@splinx.name', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'si', + phoneNumber: '837 503 2254', + label: 'Mobile', + }, + { + country: 'si', + phoneNumber: '893 405 3190', + label: 'Work', + }, + { + country: 'si', + phoneNumber: '931 402 3874', + label: 'Home', + }, + ], + title: 'Legal Assistant', + company: 'Splinx', + birthday: '1976-04-27T12:00:00.000Z', + address: '405 Canarsie Road, Richville, Virgin Islands, PO2744', + }, + attachments: _attachments, + }, + { + id: '2fb89a90-5622-4b5b-8df3-d49b85905392', + avatar: null, + name: 'Estela Lyons', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'estelalyons@mail.me', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'vg', + phoneNumber: '864 459 3205', + label: 'Mobile', + }, + { + country: 'vg', + phoneNumber: '886 524 2880', + label: 'Work', + }, + { + country: 'vg', + phoneNumber: '815 484 3420', + label: 'Home', + }, + ], + title: 'Animal Sitter', + company: 'Gonkle', + birthday: '1968-03-11T12:00:00.000Z', + address: '540 Metrotech Courtr, Garfield, American Samoa, PO2290', + }, + attachments: _attachments, + }, + { + id: '8141dd08-3a6e-4770-912c-59d0ed06dde6', + avatar: null, + name: 'Madeleine Fletcher', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'madeleinefletcher@mail.info', + label: 'Personal', + }, + { + email: 'fletcher.madeleine@genmom.biz', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'uy', + phoneNumber: '898 554 3354', + label: 'Mobile', + }, + ], + title: 'Fundraising Director', + company: 'Genmom', + birthday: '1970-07-15T12:00:00.000Z', + address: '825 Cherry Street, Foscoe, Minnesota, PO7290', + }, + attachments: _attachments, + }, + { + id: '7585015c-ada2-4f88-998d-9646865d1ad2', + avatar: 'images/avatars/male-07.jpg', + name: 'Meyer Roach', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'meyerroach@mail.co.uk', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'uz', + phoneNumber: '891 543 2053', + label: 'Mobile', + }, + { + country: 'uz', + phoneNumber: '842 564 3671', + label: 'Work', + }, + { + country: 'uz', + phoneNumber: '992 491 3514', + label: 'Home', + }, + ], + title: 'Electromedical Equipment Technician', + company: 'Zentime', + birthday: '1968-10-16T12:00:00.000Z', + address: '315 Albemarle Road, Allison, Arkansas, PO6008', + }, + attachments: _attachments, + }, + { + id: '32c73a6a-67f2-48a9-b2a1-b23da83187bb', + avatar: null, + name: 'Bolton Obrien', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'boltonobrien@mail.net', + label: 'Personal', + }, + { + email: 'obrien.bolton@enersol.ca', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'tn', + phoneNumber: '860 472 2458', + label: 'Mobile', + }, + { + country: 'tn', + phoneNumber: '887 499 3580', + label: 'Work', + }, + ], + title: 'Banker Mason', + company: 'Enersol', + birthday: '1968-09-08T12:00:00.000Z', + address: '818 Aviation Road, Geyserville, Palau, PO9655', + }, + attachments: _attachments, + }, + { + id: '114642a2-ccb7-4cb1-ad2b-5e9b6a0c1d2e', + avatar: 'images/avatars/male-09.jpg', + name: 'Barber Johnson', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'barberjohnson@mail.org', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'az', + phoneNumber: '928 567 2521', + label: 'Mobile', + }, + { + country: 'az', + phoneNumber: '898 515 2048', + label: 'Work', + }, + { + country: 'az', + phoneNumber: '935 495 3348', + label: 'Home', + }, + ], + title: 'Talent Manager', + company: 'Zounds', + birthday: '1967-03-02T12:00:00.000Z', + address: '386 Vernon Avenue, Dragoon, North Carolina, PO4559', + }, + attachments: _attachments, + }, + { + id: '310ece7d-dbb0-45d6-9e69-14c24e50fe3d', + avatar: 'images/avatars/male-10.jpg', + name: 'Cervantes Kramer', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'cervanteskramer@mail.io', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'vg', + phoneNumber: '998 498 2507', + label: 'Mobile', + }, + { + country: 'vg', + phoneNumber: '856 477 3445', + label: 'Work', + }, + ], + title: 'Motor Winder', + company: 'Xeronk', + birthday: '1992-09-04T12:00:00.000Z', + address: '238 Rochester Avenue, Lydia, Oklahoma, PO3914', + }, + attachments: _attachments, + }, + { + id: 'dcc673f6-de59-4715-94ed-8f64663d449b', + avatar: 'images/avatars/female-19.jpg', + name: 'Megan Suarez', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'megansuarez@mail.us', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'bb', + phoneNumber: '875 422 2053', + label: 'Mobile', + }, + { + country: 'bb', + phoneNumber: '861 487 2597', + label: 'Work', + }, + { + country: 'bb', + phoneNumber: '873 414 3953', + label: 'Home', + }, + ], + title: 'Bindery Machine Operator', + company: 'Cemention', + birthday: '1984-09-08T12:00:00.000Z', + address: '112 Tillary Street, Camptown, Vermont, PO8827', + }, + attachments: _attachments, + }, + { + id: '3e4ca731-d39b-4ad9-b6e0-f84e67f4b74a', + background: 'images/cards/26-640x480.jpg', + name: 'Ofelia Ratliff', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'ofeliaratliff@mail.tv', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'vu', + phoneNumber: '978 546 3699', + label: 'Mobile', + }, + { + country: 'vu', + phoneNumber: '892 551 2229', + label: 'Work', + }, + { + country: 'vu', + phoneNumber: '949 495 3479', + label: 'Home', + }, + ], + company: 'Buzzmaker', + birthday: '1988-11-11T12:00:00.000Z', + address: '951 Hampton Avenue, Bartonsville, Mississippi, PO4232', + }, + attachments: _attachments, + }, + { + id: '2012d4a5-19e4-444d-aaff-1d8b1d853650', + avatar: 'images/avatars/female-01.jpg', + name: 'Laurel Parker', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'laurelparker@mail.com', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'lu', + phoneNumber: '805 502 3677', + label: 'Mobile', + }, + { + country: 'lu', + phoneNumber: '925 527 2973', + label: 'Work', + }, + { + country: 'lu', + phoneNumber: '975 495 2977', + label: 'Home', + }, + ], + title: 'Fundraising Director', + company: 'Omnigog', + birthday: '1987-05-17T12:00:00.000Z', + address: '157 Woodhull Street, Rutherford, West Virginia, PO6646', + }, + attachments: _attachments, + }, + { + id: '012b8219-74bf-447c-af2c-66904d90a956', + avatar: 'images/avatars/female-02.jpg', + name: 'Tracy Delacruz', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'tracydelacruz@mail.name', + label: 'Personal', + }, + { + email: 'delacruz.tracy@shepard.me', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'co', + phoneNumber: '974 428 2886', + label: 'Mobile', + }, + ], + title: 'Bindery Machine Operator', + company: 'Shepard', + birthday: '1963-08-10T12:00:00.000Z', + address: '604 Merit Court, Wyano, New Hampshire, PO1641', + }, + attachments: _attachments, + }, + { + id: '8b1befd2-66a7-4981-ae52-77f01b382d18', + avatar: 'images/avatars/female-03.jpg', + name: 'Jeannette Stanton', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'jeannettestanton@mail.info', + label: 'Personal', + }, + { + email: 'stanton.jeannette@zentury.biz', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'dz', + phoneNumber: '947 561 3783', + label: 'Mobile', + }, + { + country: 'dz', + phoneNumber: '917 463 3737', + label: 'Work', + }, + { + country: 'dz', + phoneNumber: '835 510 2059', + label: 'Home', + }, + ], + title: 'Hotel Manager', + company: 'Zentury', + birthday: '1975-09-02T12:00:00.000Z', + address: '100 Menahan Street, Snyderville, Kansas, PO1006', + }, + attachments: _attachments, + }, + { + id: '844668c3-5e20-4fed-9e3a-7d274f696e61', + avatar: 'images/avatars/female-04.jpg', + name: 'Johnnie Cleveland', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'johnniecleveland@mail.co.uk', + label: 'Personal', + }, + { + email: 'cleveland.johnnie@viasia.net', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'au', + phoneNumber: '947 468 2942', + label: 'Mobile', + }, + ], + title: 'Fundraising Director', + company: 'Viasia', + birthday: '1986-03-15T12:00:00.000Z', + address: '283 Albany Avenue, Jennings, Rhode Island, PO1646', + }, + attachments: _attachments, + }, + { + id: '5a01e870-8be1-45a5-b58a-ec09c06e8f28', + avatar: 'images/avatars/female-05.jpg', + name: 'Staci Hyde', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'stacihyde@mail.ca', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'id', + phoneNumber: '944 525 2944', + label: 'Mobile', + }, + { + country: 'id', + phoneNumber: '877 500 2506', + label: 'Work', + }, + ], + title: 'Banker Mason', + company: 'Zilla', + birthday: '1975-04-22T12:00:00.000Z', + address: '560 Dooley Street, Ellerslie, Louisiana, PO1005', + }, + attachments: _attachments, + }, + { + id: '5ac1f193-f150-45f9-bfe4-b7b4e1a83ff9', + avatar: 'images/avatars/female-06.jpg', + name: 'Angela Gallagher', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'angelagallagher@mail.org', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'et', + phoneNumber: '996 514 3856', + label: 'Mobile', + }, + { + country: 'et', + phoneNumber: '903 539 2049', + label: 'Work', + }, + { + country: 'et', + phoneNumber: '938 463 3685', + label: 'Home', + }, + ], + title: 'Electromedical Equipment Technician', + company: 'Zenolux', + birthday: '1965-08-02T12:00:00.000Z', + address: '445 Remsen Avenue, Ruckersville, Delaware, PO2712', + }, + attachments: _attachments, + }, + { + id: '995df091-d78a-4bb7-840c-ba6a7d14a1bd', + avatar: 'images/avatars/male-11.jpg', + name: 'Hutchinson Levy', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'hutchinsonlevy@mail.io', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'et', + phoneNumber: '970 546 3452', + label: 'Mobile', + }, + { + country: 'et', + phoneNumber: '894 438 2430', + label: 'Work', + }, + ], + title: 'Congressional Representative', + company: 'Zytrek', + birthday: '1978-03-22T12:00:00.000Z', + address: '911 Lois Avenue, Epworth, California, PO6557', + }, + attachments: _attachments, + }, + { + id: '7184be71-a28f-4f2b-8c45-15f78cf2f825', + avatar: 'images/avatars/female-05.jpg', + name: 'Alissa Nelson', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'alissanelson@mail.us', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'lu', + phoneNumber: '893 600 2639', + label: 'Mobile', + }, + ], + title: 'Bindery Machine Operator', + company: 'Emtrak', + birthday: '1993-10-19T12:00:00.000Z', + address: '514 Sutter Avenue, Shindler, Puerto Rico, PO3862', + }, + attachments: _attachments, + }, + { + id: '325d508c-ca49-42bf-b0d5-c4a6b8da3d5c', + avatar: null, + name: 'Oliver Head', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'oliverhead@mail.tv', + label: 'Personal', + }, + ], + phoneNumbers: [ + { + country: 'bn', + phoneNumber: '977 528 3294', + label: 'Mobile', + }, + ], + title: 'Meteorologist', + company: 'Rameon', + birthday: '1967-01-05T12:00:00.000Z', + address: '569 Clermont Avenue, Movico, Marshall Islands, PO7293', + }, + attachments: _attachments, + }, + { + id: 'c674b6e1-b846-4bba-824b-0b4df0cdec48', + avatar: 'images/avatars/male-13.jpg', + name: 'Duran Barr', + about: "Hi there! I'm using FuseChat.", + details: { + emails: [ + { + email: 'duranbarr@mail.com', + label: 'Personal', + }, + { + email: 'barr.duran@hinway.name', + label: 'Work', + }, + ], + phoneNumbers: [ + { + country: 'sr', + phoneNumber: '857 457 2508', + label: 'Mobile', + }, + { + country: 'sr', + phoneNumber: '887 522 2146', + label: 'Work', + }, + { + country: 'sr', + phoneNumber: '947 574 3174', + label: 'Home', + }, + ], + title: 'Insurance Analyst', + company: 'Hinway', + birthday: '1977-11-06T12:00:00.000Z', + address: '103 Chestnut Avenue, Glenbrook, Indiana, PO2578', + }, + attachments: _attachments, + }, +]; +export const profile: any = { + id: 'cfaad35d-07a3-4447-a6c3-d8c3d54fd5df', + name: 'Brian Hughes', + email: 'hughes.brian@company.com', + avatar: 'images/avatars/brian-hughes.jpg', + about: "Hi there! I'm using FuseChat.", +}; diff --git a/frontend/src/app/mock-api/apps/llms/api.ts b/frontend/src/app/mock-api/apps/llms/api.ts new file mode 100644 index 00000000..832f829a --- /dev/null +++ b/frontend/src/app/mock-api/apps/llms/api.ts @@ -0,0 +1,38 @@ +import { Injectable } from '@angular/core'; +import { FuseMockApiService, FuseMockApiUtils } from '@fuse/lib/mock-api'; +import { + contacts as contactsData, + countries as countriesData, + tags as tagsData, +} from 'app/mock-api/apps/contacts/data'; +import { assign, cloneDeep } from 'lodash-es'; +import { from, map } from 'rxjs'; +import {llms} from "./data"; + +@Injectable({ providedIn: 'root' }) +export class ContactsMockApi { + + /** + * Constructor + */ + constructor(private _fuseMockApiService: FuseMockApiService) { + this.registerHandlers(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Register Mock API handlers + */ + registerHandlers(): void { + // ----------------------------------------------------------------------------------------------------- + // @ llms - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService.onGet('api/llms').reply(() => { + // Return the response + return [200, cloneDeep(llms)]; + }); + } +} diff --git a/frontend/src/app/mock-api/apps/llms/data.ts b/frontend/src/app/mock-api/apps/llms/data.ts new file mode 100644 index 00000000..341a0e88 --- /dev/null +++ b/frontend/src/app/mock-api/apps/llms/data.ts @@ -0,0 +1,53 @@ +/* eslint-disable */ +export const llms = [ + { + "id": "anthropic-vertex:claude-3-haiku@20240307", + "name": "Claude 3 Haiku (Vertex)", + "isConfigured": true + }, + { + "id": "anthropic-vertex:claude-3-sonnet@20240229", + "name": "Claude 3 Sonnet (Vertex)", + "isConfigured": true + }, + { + "id": "anthropic-vertex:claude-3-5-sonnet@20240620", + "name": "Claude 3.5 Sonnet (Vertex)", + "isConfigured": true + }, + { + "id": "anthropic-vertex:claude-3-opus@20240229", + "name": "Claude 3 Opus (Vertex)", + "isConfigured": true + }, + { + "id": "vertex:gemini-experimental", + "name": "Gemini experimental", + "isConfigured": true + }, + { + "id": "vertex:gemini-1.5-pro-002", + "name": "Gemini 1.5 Pro", + "isConfigured": true + }, + { + "id": "vertex:gemini-1.5-flash-002", + "name": "Gemini 1.5 Flash", + "isConfigured": true + }, + { + "id": "vertex:Llama3-405b-instruct-maas", + "name": "Llama3 405b (Vertex)", + "isConfigured": true + }, + { + "id": "blueberry:default", + "name": "Blueberry", + "isConfigured": true + }, + { + "id": "mock:mock", + "name": "mock", + "isConfigured": true + } +]; diff --git a/frontend/src/app/mock-api/common/auth/api.ts b/frontend/src/app/mock-api/common/auth/api.ts new file mode 100644 index 00000000..9813ce32 --- /dev/null +++ b/frontend/src/app/mock-api/common/auth/api.ts @@ -0,0 +1,227 @@ +import { Injectable } from '@angular/core'; +import { FuseMockApiService } from '@fuse/lib/mock-api'; +import { user as userData } from 'app/mock-api/common/user/data'; +import Base64 from 'crypto-js/enc-base64'; +import Utf8 from 'crypto-js/enc-utf8'; +import HmacSHA256 from 'crypto-js/hmac-sha256'; +import { cloneDeep } from 'lodash-es'; + +@Injectable({ providedIn: 'root' }) +export class AuthMockApi { + private readonly _secret: any; + private _user: any = userData; + + /** + * Constructor + */ + constructor(private _fuseMockApiService: FuseMockApiService) { + // Set the mock-api + this._secret = + 'YOUR_VERY_CONFIDENTIAL_SECRET_FOR_SIGNING_JWT_TOKENS!!!'; + + // Register Mock API handlers + this.registerHandlers(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Register Mock API handlers + */ + registerHandlers(): void { + // ----------------------------------------------------------------------------------------------------- + // @ Forgot password - POST + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onPost('api/auth/forgot-password', 1000) + .reply(() => [200, true]); + + // ----------------------------------------------------------------------------------------------------- + // @ Reset password - POST + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onPost('api/auth/reset-password', 1000) + .reply(() => [200, true]); + + // ----------------------------------------------------------------------------------------------------- + // @ Sign in - POST + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onPost('api/auth/sign-in', 1500) + .reply(({ request }) => { + // Sign in successful + if ( + request.body.email === 'hughes.brian@company.com' && + request.body.password === 'admin' + ) { + return [ + 200, + { + user: cloneDeep(this._user), + accessToken: this._generateJWTToken(), + tokenType: 'bearer', + }, + ]; + } + + // Invalid credentials + return [404, false]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Sign in using the access token - POST + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onPost('api/auth/sign-in-with-token') + .reply(({ request }) => { + // Get the access token + const accessToken = request.body.accessToken; + + // Verify the token + if (this._verifyJWTToken(accessToken)) { + return [ + 200, + { + user: cloneDeep(this._user), + accessToken: this._generateJWTToken(), + tokenType: 'bearer', + }, + ]; + } + + // Invalid token + return [ + 401, + { + error: 'Invalid token', + }, + ]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Sign up - POST + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService.onPost('api/auth/sign-up', 1500).reply(() => + // Simply return true + [200, true] + ); + + // ----------------------------------------------------------------------------------------------------- + // @ Unlock session - POST + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onPost('api/auth/unlock-session', 1500) + .reply(({ request }) => { + // Sign in successful + if ( + request.body.email === 'hughes.brian@company.com' && + request.body.password === 'admin' + ) { + return [ + 200, + { + user: cloneDeep(this._user), + accessToken: this._generateJWTToken(), + tokenType: 'bearer', + }, + ]; + } + + // Invalid credentials + return [404, false]; + }); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Private methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Return base64 encoded version of the given string + * + * @param source + * @private + */ + private _base64url(source: any): string { + // Encode in classical base64 + let encodedSource = Base64.stringify(source); + + // Remove padding equal characters + encodedSource = encodedSource.replace(/=+$/, ''); + + // Replace characters according to base64url specifications + encodedSource = encodedSource.replace(/\+/g, '-'); + encodedSource = encodedSource.replace(/\//g, '_'); + + // Return the base64 encoded string + return encodedSource; + } + + /** + * Generates a JWT token using CryptoJS library. + * + * This generator is for mocking purposes only and it is NOT + * safe to use it in production frontend applications! + * + * @private + */ + private _generateJWTToken(): string { + // Define token header + const header = { + alg: 'HS256', + typ: 'JWT', + }; + + // Calculate the issued at and expiration dates + const date = new Date(); + const iat = Math.floor(date.getTime() / 1000); + const exp = Math.floor(date.setDate(date.getDate() + 7) / 1000); + + // Define token payload + const payload = { + iat: iat, + iss: 'Fuse', + exp: exp, + }; + + // Stringify and encode the header + const stringifiedHeader = Utf8.parse(JSON.stringify(header)); + const encodedHeader = this._base64url(stringifiedHeader); + + // Stringify and encode the payload + const stringifiedPayload = Utf8.parse(JSON.stringify(payload)); + const encodedPayload = this._base64url(stringifiedPayload); + + // Sign the encoded header and mock-api + let signature: any = encodedHeader + '.' + encodedPayload; + signature = HmacSHA256(signature, this._secret); + signature = this._base64url(signature); + + // Build and return the token + return encodedHeader + '.' + encodedPayload + '.' + signature; + } + + /** + * Verify the given token + * + * @param token + * @private + */ + private _verifyJWTToken(token: string): boolean { + // Split the token into parts + const parts = token.split('.'); + const header = parts[0]; + const payload = parts[1]; + const signature = parts[2]; + + // Re-sign and encode the header and payload using the secret + const signatureCheck = this._base64url( + HmacSHA256(header + '.' + payload, this._secret) + ); + + // Verify that the resulting signature is valid + return signature === signatureCheck; + } +} diff --git a/frontend/src/app/mock-api/common/messages/api.ts b/frontend/src/app/mock-api/common/messages/api.ts new file mode 100644 index 00000000..9d1c15ab --- /dev/null +++ b/frontend/src/app/mock-api/common/messages/api.ts @@ -0,0 +1,161 @@ +import { Injectable } from '@angular/core'; +import { FuseMockApiService, FuseMockApiUtils } from '@fuse/lib/mock-api'; +import { messages as messagesData } from 'app/mock-api/common/messages/data'; +import { assign, cloneDeep } from 'lodash-es'; + +@Injectable({ providedIn: 'root' }) +export class MessagesMockApi { + private _messages: any = messagesData; + + /** + * Constructor + */ + constructor(private _fuseMockApiService: FuseMockApiService) { + // Register Mock API handlers + this.registerHandlers(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Register Mock API handlers + */ + registerHandlers(): void { + // ----------------------------------------------------------------------------------------------------- + // @ Messages - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onGet('api/common/messages') + .reply(() => [200, cloneDeep(this._messages)]); + + // ----------------------------------------------------------------------------------------------------- + // @ Messages - POST + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onPost('api/common/messages') + .reply(({ request }) => { + // Get the message + const newMessage = cloneDeep(request.body.message); + + // Generate a new GUID + newMessage.id = FuseMockApiUtils.guid(); + + // Unshift the new message + this._messages.unshift(newMessage); + + // Return the response + return [200, newMessage]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Messages - PATCH + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onPatch('api/common/messages') + .reply(({ request }) => { + // Get the id and message + const id = request.body.id; + const message = cloneDeep(request.body.message); + + // Prepare the updated message + let updatedMessage = null; + + // Find the message and update it + this._messages.forEach( + (item: any, index: number, messages: any[]) => { + if (item.id === id) { + // Update the message + messages[index] = assign( + {}, + messages[index], + message + ); + + // Store the updated message + updatedMessage = messages[index]; + } + } + ); + + // Return the response + return [200, updatedMessage]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Messages - DELETE + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onDelete('api/common/messages') + .reply(({ request }) => { + // Get the id + const id = request.params.get('id'); + + // Prepare the deleted message + let deletedMessage = null; + + // Find the message + const index = this._messages.findIndex( + (item: any) => item.id === id + ); + + // Store the deleted message + deletedMessage = cloneDeep(this._messages[index]); + + // Delete the message + this._messages.splice(index, 1); + + // Return the response + return [200, deletedMessage]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Mark all as read - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onGet('api/common/messages/mark-all-as-read') + .reply(() => { + // Go through all messages + this._messages.forEach( + (item: any, index: number, messages: any[]) => { + // Mark it as read + messages[index].read = true; + messages[index].seen = true; + } + ); + + // Return the response + return [200, true]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Toggle read status - POST + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onPost('api/common/messages/toggle-read-status') + .reply(({ request }) => { + // Get the message + const message = cloneDeep(request.body.message); + + // Prepare the updated message + let updatedMessage = null; + + // Find the message and update it + this._messages.forEach( + (item: any, index: number, messages: any[]) => { + if (item.id === message.id) { + // Update the message + messages[index].read = message.read; + + // Store the updated message + updatedMessage = messages[index]; + } + } + ); + + // Return the response + return [200, updatedMessage]; + }); + } +} diff --git a/frontend/src/app/mock-api/common/messages/data.ts b/frontend/src/app/mock-api/common/messages/data.ts new file mode 100644 index 00000000..49b1435a --- /dev/null +++ b/frontend/src/app/mock-api/common/messages/data.ts @@ -0,0 +1,100 @@ +/* eslint-disable */ +import { DateTime } from 'luxon'; + +/* Get the current instant */ +const now = DateTime.now(); + +export const messages = [ + { + id: '832276cc-c5e9-4fcc-8e23-d38e2e267bc9', + image: 'images/avatars/male-01.jpg', + title: 'Gary Peters', + description: 'We should talk about that at lunch!', + time: now.minus({ minutes: 25 }).toISO(), // 25 minutes ago + read: false, + }, + { + id: '608b4479-a3ac-4e26-8675-3609c52aca58', + image: 'images/avatars/male-04.jpg', + title: 'Leo Gill (Client #8817)', + description: + 'You can download the latest invoices now. Please check and let me know.', + time: now.minus({ minutes: 50 }).toISO(), // 50 minutes ago + read: false, + }, + { + id: '22148c0c-d788-4d49-9467-447677d11b76', + image: 'images/avatars/female-01.jpg', + title: 'Sarah', + description: "Don't forget to pickup Jeremy after school!", + time: now.minus({ hours: 3 }).toISO(), // 3 hours ago + read: true, + link: '/dashboards/project', + useRouter: true, + }, + { + id: '492e2917-760c-4921-aa5a-3201a857cd48', + image: 'images/avatars/female-12.jpg', + title: 'Nancy Salazar • Joy Publishing', + description: "I'll proof read your bio on next Monday.", + time: now.minus({ hours: 5 }).toISO(), // 5 hours ago + read: true, + link: '/dashboards/project', + useRouter: true, + }, + { + id: '214a46e5-cae7-4b18-9869-eabde7c7ea52', + image: 'images/avatars/male-06.jpg', + title: 'Matthew Wood', + description: + 'Dude, I heard that they are going to promote you! Congrats man, tonight the drinks are on me!', + time: now.minus({ hours: 7 }).toISO(), // 7 hours ago + read: false, + link: '/dashboards/project', + useRouter: true, + }, + { + id: '95930319-61cc-4c7e-9324-f1091865330c', + image: 'images/avatars/female-04.jpg', + title: 'Elizabeth (New assistant)', + description: + "Boss, I've sent all client invoices but Geoffrey refusing to pay.", + time: now.minus({ hours: 9 }).toISO(), // 9 hours ago + read: false, + link: '/dashboards/project', + useRouter: true, + }, + { + id: '802935e9-9577-48bc-98d1-308a4872afd7', + image: 'images/avatars/male-06.jpg', + title: 'William Bell', + description: + 'Did you see this game? We should hang out and give it a shot sometime.', + time: now.minus({ day: 1 }).toISO(), // 1 day ago + read: true, + link: 'https://www.google.com', + useRouter: false, + }, + { + id: '059f3738-633b-48ea-ad83-19016ce24c62', + image: 'images/avatars/female-09.jpg', + title: 'Cheryl Obrien - HR', + description: + "Why did't you still look at the kitten pictures I've sent to you!", + time: now.minus({ day: 3 }).toISO(), // 3 days ago + read: false, + link: '/dashboards/project', + useRouter: true, + }, + { + id: '5c2bb44d-5ca7-42ff-ad7e-46ced9f49a24', + image: 'images/avatars/female-15.jpg', + title: 'Joan Jones - Tech', + description: + 'Dude, Cheryl keeps bugging me with kitten pictures all the time :( What are we gonna do about it?', + time: now.minus({ day: 4 }).toISO(), // 4 days ago + read: true, + link: '/dashboards/project', + useRouter: true, + }, +]; diff --git a/frontend/src/app/mock-api/common/navigation/api.ts b/frontend/src/app/mock-api/common/navigation/api.ts new file mode 100644 index 00000000..a4894834 --- /dev/null +++ b/frontend/src/app/mock-api/common/navigation/api.ts @@ -0,0 +1,88 @@ +import { Injectable } from '@angular/core'; +import { FuseNavigationItem } from '@fuse/components/navigation'; +import { FuseMockApiService } from '@fuse/lib/mock-api'; +import { + compactNavigation, + defaultNavigation, + futuristicNavigation, + horizontalNavigation, +} from 'app/mock-api/common/navigation/data'; +import { cloneDeep } from 'lodash-es'; + +@Injectable({ providedIn: 'root' }) +export class NavigationMockApi { + private readonly _compactNavigation: FuseNavigationItem[] = + compactNavigation; + private readonly _defaultNavigation: FuseNavigationItem[] = + defaultNavigation; + private readonly _futuristicNavigation: FuseNavigationItem[] = + futuristicNavigation; + private readonly _horizontalNavigation: FuseNavigationItem[] = + horizontalNavigation; + + /** + * Constructor + */ + constructor(private _fuseMockApiService: FuseMockApiService) { + // Register Mock API handlers + this.registerHandlers(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Register Mock API handlers + */ + registerHandlers(): void { + // ----------------------------------------------------------------------------------------------------- + // @ Navigation - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService.onGet('api/common/navigation').reply(() => { + // Fill compact navigation children using the default navigation + this._compactNavigation.forEach((compactNavItem) => { + this._defaultNavigation.forEach((defaultNavItem) => { + if (defaultNavItem.id === compactNavItem.id) { + compactNavItem.children = cloneDeep( + defaultNavItem.children + ); + } + }); + }); + + // Fill futuristic navigation children using the default navigation + this._futuristicNavigation.forEach((futuristicNavItem) => { + this._defaultNavigation.forEach((defaultNavItem) => { + if (defaultNavItem.id === futuristicNavItem.id) { + futuristicNavItem.children = cloneDeep( + defaultNavItem.children + ); + } + }); + }); + + // Fill horizontal navigation children using the default navigation + this._horizontalNavigation.forEach((horizontalNavItem) => { + this._defaultNavigation.forEach((defaultNavItem) => { + if (defaultNavItem.id === horizontalNavItem.id) { + horizontalNavItem.children = cloneDeep( + defaultNavItem.children + ); + } + }); + }); + + // Return the response + return [ + 200, + { + compact: cloneDeep(this._compactNavigation), + default: cloneDeep(this._defaultNavigation), + futuristic: cloneDeep(this._futuristicNavigation), + horizontal: cloneDeep(this._horizontalNavigation), + }, + ]; + }); + } +} diff --git a/frontend/src/app/mock-api/common/navigation/data.ts b/frontend/src/app/mock-api/common/navigation/data.ts new file mode 100644 index 00000000..4c2d9361 --- /dev/null +++ b/frontend/src/app/mock-api/common/navigation/data.ts @@ -0,0 +1,50 @@ +/* eslint-disable */ +import { FuseNavigationItem } from '@fuse/components/navigation'; + +export const defaultNavigation: FuseNavigationItem[] = [ + { + id: 'apps.chat', + title: 'Chat', + type: 'basic', + icon: 'heroicons_outline:chat-bubble-bottom-center-text', + link: '/apps/chat', + }, + // { + // id: 'assistants', + // title: 'Assistants', + // type: 'basic', + // icon: 'mat_outline:support_agent', + // link: '/assistants', + // }, + { + id: 'agents', + title: 'Agents', + type: 'basic', + icon: 'heroicons_outline:squares-2x2', + link: '/agents/list', + }, + { + id: 'new-agent', + title: 'New Agent', + type: 'basic', + icon: 'heroicons_outline:squares-plus', + link: '/agents/new', + }, + { + id: 'actions', + title: 'Actions', + type: 'basic', + icon: 'heroicons_outline:server-stack', + link: '/actions', + }, + { + id: 'codereviews', + title: 'Code reviews', + type: 'basic', + icon: 'heroicons_outline:code-bracket-square', + link: '/code-reviews', + } +]; +export const compactNavigation: FuseNavigationItem[] = defaultNavigation; +export const futuristicNavigation: FuseNavigationItem[] = defaultNavigation; +export const horizontalNavigation: FuseNavigationItem[] = defaultNavigation; diff --git a/frontend/src/app/mock-api/common/notifications/api.ts b/frontend/src/app/mock-api/common/notifications/api.ts new file mode 100644 index 00000000..cc35ab90 --- /dev/null +++ b/frontend/src/app/mock-api/common/notifications/api.ts @@ -0,0 +1,161 @@ +import { Injectable } from '@angular/core'; +import { FuseMockApiService, FuseMockApiUtils } from '@fuse/lib/mock-api'; +import { notifications as notificationsData } from 'app/mock-api/common/notifications/data'; +import { assign, cloneDeep } from 'lodash-es'; + +@Injectable({ providedIn: 'root' }) +export class NotificationsMockApi { + private _notifications: any = notificationsData; + + /** + * Constructor + */ + constructor(private _fuseMockApiService: FuseMockApiService) { + // Register Mock API handlers + this.registerHandlers(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Register Mock API handlers + */ + registerHandlers(): void { + // ----------------------------------------------------------------------------------------------------- + // @ Notifications - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onGet('api/common/notifications') + .reply(() => [200, cloneDeep(this._notifications)]); + + // ----------------------------------------------------------------------------------------------------- + // @ Notifications - POST + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onPost('api/common/notifications') + .reply(({ request }) => { + // Get the notification + const newNotification = cloneDeep(request.body.notification); + + // Generate a new GUID + newNotification.id = FuseMockApiUtils.guid(); + + // Unshift the new notification + this._notifications.unshift(newNotification); + + // Return the response + return [200, newNotification]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Notifications - PATCH + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onPatch('api/common/notifications') + .reply(({ request }) => { + // Get the id and notification + const id = request.body.id; + const notification = cloneDeep(request.body.notification); + + // Prepare the updated notification + let updatedNotification = null; + + // Find the notification and update it + this._notifications.forEach( + (item: any, index: number, notifications: any[]) => { + if (item.id === id) { + // Update the notification + notifications[index] = assign( + {}, + notifications[index], + notification + ); + + // Store the updated notification + updatedNotification = notifications[index]; + } + } + ); + + // Return the response + return [200, updatedNotification]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Notifications - DELETE + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onDelete('api/common/notifications') + .reply(({ request }) => { + // Get the id + const id = request.params.get('id'); + + // Prepare the deleted notification + let deletedNotification = null; + + // Find the notification + const index = this._notifications.findIndex( + (item: any) => item.id === id + ); + + // Store the deleted notification + deletedNotification = cloneDeep(this._notifications[index]); + + // Delete the notification + this._notifications.splice(index, 1); + + // Return the response + return [200, deletedNotification]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Mark all as read - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onGet('api/common/notifications/mark-all-as-read') + .reply(() => { + // Go through all notifications + this._notifications.forEach( + (item: any, index: number, notifications: any[]) => { + // Mark it as read + notifications[index].read = true; + notifications[index].seen = true; + } + ); + + // Return the response + return [200, true]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Toggle read status - POST + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onPost('api/common/notifications/toggle-read-status') + .reply(({ request }) => { + // Get the notification + const notification = cloneDeep(request.body.notification); + + // Prepare the updated notification + let updatedNotification = null; + + // Find the notification and update it + this._notifications.forEach( + (item: any, index: number, notifications: any[]) => { + if (item.id === notification.id) { + // Update the notification + notifications[index].read = notification.read; + + // Store the updated notification + updatedNotification = notifications[index]; + } + } + ); + + // Return the response + return [200, updatedNotification]; + }); + } +} diff --git a/frontend/src/app/mock-api/common/notifications/data.ts b/frontend/src/app/mock-api/common/notifications/data.ts new file mode 100644 index 00000000..7b1d24eb --- /dev/null +++ b/frontend/src/app/mock-api/common/notifications/data.ts @@ -0,0 +1,96 @@ +/* eslint-disable */ +import { DateTime } from 'luxon'; + +/* Get the current instant */ +const now = DateTime.now(); + +export const notifications = [ + { + id: '493190c9-5b61-4912-afe5-78c21f1044d7', + icon: 'heroicons_mini:star', + title: 'Daily challenges', + description: 'Your submission has been accepted', + time: now.minus({ minute: 25 }).toISO(), // 25 minutes ago + read: false, + }, + { + id: '6e3e97e5-effc-4fb7-b730-52a151f0b641', + image: 'images/avatars/male-04.jpg', + description: + 'Leo Gill added you to Top Secret Project group and assigned you as a Project Manager', + time: now.minus({ minute: 50 }).toISO(), // 50 minutes ago + read: true, + link: '/dashboards/project', + useRouter: true, + }, + { + id: 'b91ccb58-b06c-413b-b389-87010e03a120', + icon: 'heroicons_mini:envelope', + title: 'Mailbox', + description: 'You have 15 unread mails across 3 mailboxes', + time: now.minus({ hour: 3 }).toISO(), // 3 hours ago + read: false, + link: '/dashboards/project', + useRouter: true, + }, + { + id: '541416c9-84a7-408a-8d74-27a43c38d797', + icon: 'heroicons_mini:arrow-path', + title: 'Cron jobs', + description: 'Your Docker container is ready to publish', + time: now.minus({ hour: 5 }).toISO(), // 5 hours ago + read: false, + link: '/dashboards/project', + useRouter: true, + }, + { + id: 'ef7b95a7-8e8b-4616-9619-130d9533add9', + image: 'images/avatars/male-06.jpg', + description: + 'Roger Murray accepted your friend request', + time: now.minus({ hour: 7 }).toISO(), // 7 hours ago + read: true, + link: '/dashboards/project', + useRouter: true, + }, + { + id: 'eb8aa470-635e-461d-88e1-23d9ea2a5665', + image: 'images/avatars/female-04.jpg', + description: 'Sophie Stone sent you a direct message', + time: now.minus({ hour: 9 }).toISO(), // 9 hours ago + read: true, + link: '/dashboards/project', + useRouter: true, + }, + { + id: 'b85c2338-cc98-4140-bbf8-c226ce4e395e', + icon: 'heroicons_mini:envelope', + title: 'Mailbox', + description: 'You have 3 new mails', + time: now.minus({ day: 1 }).toISO(), // 1 day ago + read: true, + link: '/dashboards/project', + useRouter: true, + }, + { + id: '8f8e1bf9-4661-4939-9e43-390957b60f42', + icon: 'heroicons_mini:star', + title: 'Daily challenges', + description: + 'Your submission has been accepted and you are ready to sign-up for the final assigment which will be ready in 2 days', + time: now.minus({ day: 3 }).toISO(), // 3 days ago + read: true, + link: '/dashboards/project', + useRouter: true, + }, + { + id: '30af917b-7a6a-45d1-822f-9e7ad7f8bf69', + icon: 'heroicons_mini:arrow-path', + title: 'Cron jobs', + description: 'Your Vagrant container is ready to download', + time: now.minus({ day: 4 }).toISO(), // 4 days ago + read: true, + link: '/dashboards/project', + useRouter: true, + }, +]; diff --git a/frontend/src/app/mock-api/common/shortcuts/api.ts b/frontend/src/app/mock-api/common/shortcuts/api.ts new file mode 100644 index 00000000..61bae69c --- /dev/null +++ b/frontend/src/app/mock-api/common/shortcuts/api.ts @@ -0,0 +1,113 @@ +import { Injectable } from '@angular/core'; +import { FuseMockApiService, FuseMockApiUtils } from '@fuse/lib/mock-api'; +import { shortcuts as shortcutsData } from 'app/mock-api/common/shortcuts/data'; +import { assign, cloneDeep } from 'lodash-es'; + +@Injectable({ providedIn: 'root' }) +export class ShortcutsMockApi { + private _shortcuts: any = shortcutsData; + + /** + * Constructor + */ + constructor(private _fuseMockApiService: FuseMockApiService) { + // Register Mock API handlers + this.registerHandlers(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Register Mock API handlers + */ + registerHandlers(): void { + // ----------------------------------------------------------------------------------------------------- + // @ Shortcuts - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onGet('api/common/shortcuts') + .reply(() => [200, cloneDeep(this._shortcuts)]); + + // ----------------------------------------------------------------------------------------------------- + // @ Shortcuts - POST + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onPost('api/common/shortcuts') + .reply(({ request }) => { + // Get the shortcut + const newShortcut = cloneDeep(request.body.shortcut); + + // Generate a new GUID + newShortcut.id = FuseMockApiUtils.guid(); + + // Unshift the new shortcut + this._shortcuts.unshift(newShortcut); + + // Return the response + return [200, newShortcut]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Shortcuts - PATCH + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onPatch('api/common/shortcuts') + .reply(({ request }) => { + // Get the id and shortcut + const id = request.body.id; + const shortcut = cloneDeep(request.body.shortcut); + + // Prepare the updated shortcut + let updatedShortcut = null; + + // Find the shortcut and update it + this._shortcuts.forEach( + (item: any, index: number, shortcuts: any[]) => { + if (item.id === id) { + // Update the shortcut + shortcuts[index] = assign( + {}, + shortcuts[index], + shortcut + ); + + // Store the updated shortcut + updatedShortcut = shortcuts[index]; + } + } + ); + + // Return the response + return [200, updatedShortcut]; + }); + + // ----------------------------------------------------------------------------------------------------- + // @ Shortcuts - DELETE + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onDelete('api/common/shortcuts') + .reply(({ request }) => { + // Get the id + const id = request.params.get('id'); + + // Prepare the deleted shortcut + let deletedShortcut = null; + + // Find the shortcut + const index = this._shortcuts.findIndex( + (item: any) => item.id === id + ); + + // Store the deleted shortcut + deletedShortcut = cloneDeep(this._shortcuts[index]); + + // Delete the shortcut + this._shortcuts.splice(index, 1); + + // Return the response + return [200, deletedShortcut]; + }); + } +} diff --git a/frontend/src/app/mock-api/common/shortcuts/data.ts b/frontend/src/app/mock-api/common/shortcuts/data.ts new file mode 100644 index 00000000..c699ec61 --- /dev/null +++ b/frontend/src/app/mock-api/common/shortcuts/data.ts @@ -0,0 +1,67 @@ +/* eslint-disable */ +export const shortcuts = [ + { + id: 'a1ae91d3-e2cb-459b-9be9-a184694f548b', + label: 'Changelog', + description: 'List of changes', + icon: 'heroicons_outline:clipboard-document-list', + link: '/docs/changelog', + useRouter: true, + }, + { + id: '989ce876-c177-4d71-a749-1953c477f825', + label: 'Documentation', + description: 'Getting started', + icon: 'heroicons_outline:book-open', + link: '/docs/guides/getting-started/introduction', + useRouter: true, + }, + { + id: '2496f42e-2f25-4e34-83d5-3ff9568fd984', + label: 'Help center', + description: 'FAQs and guides', + icon: 'heroicons_outline:information-circle', + link: '/apps/help-center', + useRouter: true, + }, + { + id: '3c48e75e-2ae7-4b73-938a-12dc655be28b', + label: 'Dashboard', + description: 'User analytics', + icon: 'heroicons_outline:chart-pie', + link: '/dashboards/analytics', + useRouter: true, + }, + { + id: '2daac375-a2f7-4393-b4d7-ce6061628b66', + label: 'Mailbox', + description: '5 new e-mails', + icon: 'heroicons_outline:envelope', + link: 'apps/mailbox', + useRouter: true, + }, + { + id: '56a0a561-17e7-40b3-bd75-0b6cef230b7e', + label: 'Tasks', + description: '12 unfinished tasks', + icon: 'heroicons_outline:check-circle', + link: '/apps/tasks', + useRouter: true, + }, + { + id: 'f5daf93e-b6f3-4199-8a0c-b951e92a6cb8', + label: 'Contacts', + description: 'List all contacts', + icon: 'heroicons_outline:user-group', + link: '/apps/contacts', + useRouter: true, + }, + { + id: '0a240ab8-e19d-4503-bf68-20013030d526', + label: 'Reload', + description: 'Reload the app', + icon: 'heroicons_outline:arrow-path', + link: '/dashboards/project', + useRouter: false, + }, +]; diff --git a/frontend/src/app/mock-api/common/user/api.ts b/frontend/src/app/mock-api/common/user/api.ts new file mode 100644 index 00000000..97b32d40 --- /dev/null +++ b/frontend/src/app/mock-api/common/user/api.ts @@ -0,0 +1,49 @@ +import { Injectable } from '@angular/core'; +import { FuseMockApiService } from '@fuse/lib/mock-api'; +import { user as userData } from 'app/mock-api/common/user/data'; +import { assign, cloneDeep } from 'lodash-es'; + +@Injectable({ providedIn: 'root' }) +export class UserMockApi { + private _user: any = userData; + + /** + * Constructor + */ + constructor(private _fuseMockApiService: FuseMockApiService) { + // Register Mock API handlers + this.registerHandlers(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Register Mock API handlers + */ + registerHandlers(): void { + // ----------------------------------------------------------------------------------------------------- + // @ User - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onGet('api/common/user') + .reply(() => [200, cloneDeep(this._user)]); + + // ----------------------------------------------------------------------------------------------------- + // @ User - PATCH + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onPatch('api/common/user') + .reply(({ request }) => { + // Get the user mock-api + const user = cloneDeep(request.body.user); + + // Update the user mock-api + this._user = assign({}, this._user, user); + + // Return the response + return [200, cloneDeep(this._user)]; + }); + } +} diff --git a/frontend/src/app/mock-api/common/user/data.ts b/frontend/src/app/mock-api/common/user/data.ts new file mode 100644 index 00000000..7b5571e4 --- /dev/null +++ b/frontend/src/app/mock-api/common/user/data.ts @@ -0,0 +1,8 @@ +/* eslint-disable */ +export const user = { + id: 'cfaad35d-07a3-4447-a6c3-d8c3d54fd5df', + name: 'Brian Hughes', + email: 'hughes.brian@company.com', + avatar: 'images/avatars/brian-hughes.jpg', + status: 'online', +}; diff --git a/frontend/src/app/mock-api/index.ts b/frontend/src/app/mock-api/index.ts new file mode 100644 index 00000000..51b9d848 --- /dev/null +++ b/frontend/src/app/mock-api/index.ts @@ -0,0 +1,23 @@ +import { AcademyMockApi } from 'app/mock-api/apps/academy/api'; +import { ChatMockApi } from 'app/mock-api/apps/chat/api'; +import { AuthMockApi } from 'app/mock-api/common/auth/api'; +import { MessagesMockApi } from 'app/mock-api/common/messages/api'; +import { NavigationMockApi } from 'app/mock-api/common/navigation/api'; +import { NotificationsMockApi } from 'app/mock-api/common/notifications/api'; +import { ShortcutsMockApi } from 'app/mock-api/common/shortcuts/api'; +import { UserMockApi } from 'app/mock-api/common/user/api'; +import { ActivitiesMockApi } from 'app/mock-api/pages/activities/api'; +import { IconsMockApi } from 'app/mock-api/ui/icons/api'; + +export const mockApiServices = [ + AcademyMockApi, + ActivitiesMockApi, + AuthMockApi, + ChatMockApi, + IconsMockApi, + MessagesMockApi, + NavigationMockApi, + NotificationsMockApi, + ShortcutsMockApi, + UserMockApi, +]; diff --git a/frontend/src/app/mock-api/pages/activities/api.ts b/frontend/src/app/mock-api/pages/activities/api.ts new file mode 100644 index 00000000..bbfd7dcd --- /dev/null +++ b/frontend/src/app/mock-api/pages/activities/api.ts @@ -0,0 +1,33 @@ +import { Injectable } from '@angular/core'; +import { FuseMockApiService } from '@fuse/lib/mock-api'; +import { activities as activitiesData } from 'app/mock-api/pages/activities/data'; +import { cloneDeep } from 'lodash-es'; + +@Injectable({ providedIn: 'root' }) +export class ActivitiesMockApi { + private _activities: any = activitiesData; + + /** + * Constructor + */ + constructor(private _fuseMockApiService: FuseMockApiService) { + // Register Mock API handlers + this.registerHandlers(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Register Mock API handlers + */ + registerHandlers(): void { + // ----------------------------------------------------------------------------------------------------- + // @ Activities - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onGet('api/pages/activities') + .reply(() => [200, cloneDeep(this._activities)]); + } +} diff --git a/frontend/src/app/mock-api/pages/activities/data.ts b/frontend/src/app/mock-api/pages/activities/data.ts new file mode 100644 index 00000000..8040efa3 --- /dev/null +++ b/frontend/src/app/mock-api/pages/activities/data.ts @@ -0,0 +1,95 @@ +/* eslint-disable */ +import { DateTime } from 'luxon'; + +/* Get the current instant */ +const now = DateTime.now(); + +export const activities = [ + { + id: '493190c9-5b61-4912-afe5-78c21f1044d7', + icon: 'heroicons_solid:star', + description: 'Your submission has been accepted', + date: now.minus({ minutes: 25 }).toISO(), // 25 minutes ago + extraContent: `
Congratulations for your acceptance!

+
Hi Brian,
Your submission has been accepted and you are ready to move into the next phase. Once you are ready, reach out to me and we will ...
`, + }, + { + id: '6e3e97e5-effc-4fb7-b730-52a151f0b641', + image: 'images/avatars/male-04.jpg', + description: + 'Leo Gill added you to Top Secret Project group and assigned you as a Project Manager', + date: now.minus({ minutes: 50 }).toISO(), // 50 minutes ago + linkedContent: 'Top Secret Project', + link: '/dashboards/project', + useRouter: true, + }, + { + id: 'b91ccb58-b06c-413b-b389-87010e03a120', + icon: 'heroicons_solid:envelope', + description: 'You have 15 unread mails across 3 mailboxes', + date: now.minus({ hours: 3 }).toISO(), // 3 hours ago + linkedContent: 'Mailbox', + link: '/apps/mailbox', + useRouter: true, + }, + { + id: '541416c9-84a7-408a-8d74-27a43c38d797', + icon: 'heroicons_solid:arrow-path', + description: + 'Your Docker container is ready to publish', + date: now.minus({ hours: 5 }).toISO(), // 5 hours ago + linkedContent: 'Download the container', + link: '.', + useRouter: true, + }, + { + id: 'ef7b95a7-8e8b-4616-9619-130d9533add9', + image: 'images/avatars/male-06.jpg', + description: + 'Roger Murray accepted your friend request', + date: now.minus({ hours: 7 }).toISO(), // 7 hours ago + extraContent: `You have 8 mutual friends.`, + }, + { + id: 'eb8aa470-635e-461d-88e1-23d9ea2a5665', + image: 'images/avatars/female-04.jpg', + description: 'Sophie Stone sent you a direct message', + date: now.minus({ hours: 9 }).toISO(), // 9 hours ago + }, + { + id: 'b85c2338-cc98-4140-bbf8-c226ce4e395e', + icon: 'heroicons_solid:envelope', + description: 'You have 3 new mails', + date: now.minus({ day: 1 }).toISO(), // 1 day ago + extraContent: `
    +
  1. Please review and sign the attached agreement
  2. +
  3. Delivery address confirmation
  4. +
  5. Previous clients and their invoices
  6. +
`, + linkedContent: 'Mailbox', + link: '/apps/mailbox', + useRouter: true, + }, + { + id: 'fd0f01b4-f3de-4333-add5-cd86850279f8', + image: 'images/avatars/female-02.jpg', + description: 'Tina Harris started a chat with you', + date: now.minus({ day: 1 }).toISO(), // 1 day ago, + linkedContent: 'Go to Chat (Tina Harris)', + link: '/apps/chat/5636c0ba-fa47-42ca-9160-27340583041e', + useRouter: true, + }, + { + id: '8f8e1bf9-4661-4939-9e43-390957b60f42', + icon: 'heroicons_solid:star', + description: + 'Your submission has been accepted and you are ready to sign-up for the final assigment which will be ready in 2 days', + date: now.minus({ days: 3 }).toISO(), // 3 days ago + }, + { + id: '30af917b-7a6a-45d1-822f-9e7ad7f8bf69', + icon: 'heroicons_solid:arrow-path', + description: 'Your Vagrant container is ready to download', + date: now.minus({ day: 4 }).toISO(), // 4 days ago + }, +]; diff --git a/frontend/src/app/mock-api/ui/icons/api.ts b/frontend/src/app/mock-api/ui/icons/api.ts new file mode 100644 index 00000000..6e01d4b8 --- /dev/null +++ b/frontend/src/app/mock-api/ui/icons/api.ts @@ -0,0 +1,131 @@ +import { Injectable } from '@angular/core'; +import { FuseMockApiService } from '@fuse/lib/mock-api'; +import { feather, heroicons, material } from 'app/mock-api/ui/icons/data'; +import { cloneDeep } from 'lodash-es'; + +@Injectable({ providedIn: 'root' }) +export class IconsMockApi { + private readonly _feather: any = feather; + private readonly _heroicons: any = heroicons; + private readonly _material: any = material; + + /** + * Constructor + */ + constructor(private _fuseMockApiService: FuseMockApiService) { + // Register Mock API handlers + this.registerHandlers(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Register Mock API handlers + */ + registerHandlers(): void { + // ----------------------------------------------------------------------------------------------------- + // @ Feather icons - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService.onGet('api/ui/icons/feather').reply(() => [ + 200, + { + namespace: 'feather', + name: 'Feather', + grid: 'icon-size-6', + list: cloneDeep(this._feather), + }, + ]); + + // ----------------------------------------------------------------------------------------------------- + // @ Heroicons outline icons - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onGet('api/ui/icons/heroicons-outline') + .reply(() => [ + 200, + { + namespace: 'heroicons_outline', + name: 'Heroicons Outline', + grid: 'icon-size-6', + list: cloneDeep(this._heroicons), + }, + ]); + + // ----------------------------------------------------------------------------------------------------- + // @ Heroicons solid icons - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onGet('api/ui/icons/heroicons-solid') + .reply(() => [ + 200, + { + namespace: 'heroicons_solid', + name: 'Heroicons Solid', + grid: 'icon-size-6', + list: cloneDeep(this._heroicons), + }, + ]); + + // ----------------------------------------------------------------------------------------------------- + // @ Heroicons mini icons - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onGet('api/ui/icons/heroicons-mini') + .reply(() => [ + 200, + { + namespace: 'heroicons_mini', + name: 'Heroicons Mini', + grid: 'icon-size-5', + list: cloneDeep(this._heroicons), + }, + ]); + + // ----------------------------------------------------------------------------------------------------- + // @ Material solid icons - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onGet('api/ui/icons/material-solid') + .reply(() => [ + 200, + { + namespace: 'mat_solid', + name: 'Material Solid', + grid: 'icon-size-6', + list: cloneDeep(this._material), + }, + ]); + + // ----------------------------------------------------------------------------------------------------- + // @ Material outline icons - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onGet('api/ui/icons/material-outline') + .reply(() => [ + 200, + { + namespace: 'mat_outline', + name: 'Material Outline', + grid: 'icon-size-6', + list: cloneDeep(this._material), + }, + ]); + + // ----------------------------------------------------------------------------------------------------- + // @ Material twotone icons - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onGet('api/ui/icons/material-twotone') + .reply(() => [ + 200, + { + namespace: '', + name: 'Material Twotone', + grid: 'icon-size-6', + list: cloneDeep(this._material), + }, + ]); + } +} diff --git a/frontend/src/app/mock-api/ui/icons/data.ts b/frontend/src/app/mock-api/ui/icons/data.ts new file mode 100644 index 00000000..3fa2a728 --- /dev/null +++ b/frontend/src/app/mock-api/ui/icons/data.ts @@ -0,0 +1,2376 @@ +/* eslint-disable */ + +// Updated at: 20210425 - 1792 icons +export const material = [ + '10k', + '10mp', + '11mp', + '12mp', + '13mp', + '14mp', + '15mp', + '16mp', + '17mp', + '18mp', + '19mp', + '1k', + '1k_plus', + '1x_mobiledata', + '20mp', + '21mp', + '22mp', + '23mp', + '24mp', + '2k', + '2k_plus', + '2mp', + '30fps', + '30fps_select', + '360', + '3d_rotation', + '3g_mobiledata', + '3k', + '3k_plus', + '3mp', + '3p', + '4g_mobiledata', + '4g_plus_mobiledata', + '4k', + '4k_plus', + '4mp', + '5g', + '5k', + '5k_plus', + '5mp', + '60fps', + '60fps_select', + '6_ft_apart', + '6k', + '6k_plus', + '6mp', + '7k', + '7k_plus', + '7mp', + '8k', + '8k_plus', + '8mp', + '9k', + '9k_plus', + '9mp', + 'ac_unit', + 'access_alarm', + 'access_alarms', + 'access_time', + 'access_time_filled', + 'accessibility', + 'accessibility_new', + 'accessible', + 'accessible_forward', + 'account_balance', + 'account_balance_wallet', + 'account_box', + 'account_circle', + 'account_tree', + 'ad_units', + 'adb', + 'add', + 'add_a_photo', + 'add_alarm', + 'add_alert', + 'add_box', + 'add_business', + 'add_chart', + 'add_circle', + 'add_circle_outline', + 'add_comment', + 'add_ic_call', + 'add_link', + 'add_location', + 'add_location_alt', + 'add_moderator', + 'add_photo_alternate', + 'add_reaction', + 'add_road', + 'add_shopping_cart', + 'add_task', + 'add_to_drive', + 'add_to_home_screen', + 'add_to_photos', + 'add_to_queue', + 'addchart', + 'adjust', + 'admin_panel_settings', + 'ads_click', + 'agriculture', + 'air', + 'airline_seat_flat', + 'airline_seat_flat_angled', + 'airline_seat_individual_suite', + 'airline_seat_legroom_extra', + 'airline_seat_legroom_normal', + 'airline_seat_legroom_reduced', + 'airline_seat_recline_extra', + 'airline_seat_recline_normal', + 'airplane_ticket', + 'airplanemode_active', + 'airplanemode_inactive', + 'airplay', + 'airport_shuttle', + 'alarm', + 'alarm_add', + 'alarm_off', + 'alarm_on', + 'album', + 'align_horizontal_center', + 'align_horizontal_left', + 'align_horizontal_right', + 'align_vertical_bottom', + 'align_vertical_center', + 'align_vertical_top', + 'all_inbox', + 'all_inclusive', + 'all_out', + 'alt_route', + 'alternate_email', + 'analytics', + 'anchor', + 'android', + 'animation', + 'announcement', + 'aod', + 'apartment', + 'api', + 'app_blocking', + 'app_registration', + 'app_settings_alt', + 'approval', + 'apps', + 'architecture', + 'archive', + 'area_chart', + 'arrow_back', + 'arrow_back_ios', + 'arrow_back_ios_new', + 'arrow_circle_down', + 'arrow_circle_up', + 'arrow_downward', + 'arrow_drop_down', + 'arrow_drop_down_circle', + 'arrow_drop_up', + 'arrow_forward', + 'arrow_forward_ios', + 'arrow_left', + 'arrow_right', + 'arrow_right_alt', + 'arrow_upward', + 'art_track', + 'article', + 'aspect_ratio', + 'assessment', + 'assignment', + 'assignment_ind', + 'assignment_late', + 'assignment_return', + 'assignment_returned', + 'assignment_turned_in', + 'assistant', + 'assistant_direction', + 'assistant_photo', + 'atm', + 'attach_email', + 'attach_file', + 'attach_money', + 'attachment', + 'attractions', + 'attribution', + 'audiotrack', + 'auto_awesome', + 'auto_awesome_mosaic', + 'auto_awesome_motion', + 'auto_delete', + 'auto_fix_high', + 'auto_fix_normal', + 'auto_fix_off', + 'auto_graph', + 'auto_stories', + 'autofps_select', + 'autorenew', + 'av_timer', + 'baby_changing_station', + 'back_hand', + 'backpack', + 'backspace', + 'backup', + 'backup_table', + 'badge', + 'bakery_dining', + 'balcony', + 'ballot', + 'bar_chart', + 'batch_prediction', + 'bathroom', + 'bathtub', + 'battery_alert', + 'battery_charging_full', + 'battery_full', + 'battery_saver', + 'battery_std', + 'battery_unknown', + 'beach_access', + 'bed', + 'bedroom_baby', + 'bedroom_child', + 'bedroom_parent', + 'bedtime', + 'beenhere', + 'bento', + 'bike_scooter', + 'biotech', + 'blender', + 'block', + 'bloodtype', + 'bluetooth', + 'bluetooth_audio', + 'bluetooth_connected', + 'bluetooth_disabled', + 'bluetooth_drive', + 'bluetooth_searching', + 'blur_circular', + 'blur_linear', + 'blur_off', + 'blur_on', + 'bolt', + 'book', + 'book_online', + 'bookmark', + 'bookmark_add', + 'bookmark_added', + 'bookmark_border', + 'bookmark_remove', + 'bookmarks', + 'border_all', + 'border_bottom', + 'border_clear', + 'border_color', + 'border_horizontal', + 'border_inner', + 'border_left', + 'border_outer', + 'border_right', + 'border_style', + 'border_top', + 'border_vertical', + 'branding_watermark', + 'breakfast_dining', + 'brightness_1', + 'brightness_2', + 'brightness_3', + 'brightness_4', + 'brightness_5', + 'brightness_6', + 'brightness_7', + 'brightness_auto', + 'brightness_high', + 'brightness_low', + 'brightness_medium', + 'broken_image', + 'browser_not_supported', + 'brunch_dining', + 'brush', + 'bubble_chart', + 'bug_report', + 'build', + 'build_circle', + 'bungalow', + 'burst_mode', + 'bus_alert', + 'business', + 'business_center', + 'cabin', + 'cable', + 'cached', + 'cake', + 'calculate', + 'calendar_today', + 'calendar_view_day', + 'calendar_view_month', + 'calendar_view_week', + 'call', + 'call_end', + 'call_made', + 'call_merge', + 'call_missed', + 'call_missed_outgoing', + 'call_received', + 'call_split', + 'call_to_action', + 'camera', + 'camera_alt', + 'camera_enhance', + 'camera_front', + 'camera_indoor', + 'camera_outdoor', + 'camera_rear', + 'camera_roll', + 'cameraswitch', + 'campaign', + 'cancel', + 'cancel_presentation', + 'cancel_schedule_send', + 'car_rental', + 'car_repair', + 'card_giftcard', + 'card_membership', + 'card_travel', + 'carpenter', + 'cases', + 'casino', + 'cast', + 'cast_connected', + 'cast_for_education', + 'catching_pokemon', + 'category', + 'celebration', + 'cell_wifi', + 'center_focus_strong', + 'center_focus_weak', + 'chair', + 'chair_alt', + 'chalet', + 'change_circle', + 'change_history', + 'charging_station', + 'chat', + 'chat_bubble', + 'chat_bubble_outline', + 'check', + 'check_box', + 'check_box_outline_blank', + 'check_circle', + 'check_circle_outline', + 'checklist', + 'checklist_rtl', + 'checkroom', + 'chevron_left', + 'chevron_right', + 'child_care', + 'child_friendly', + 'chrome_reader_mode', + 'circle', + 'circle_notifications', + 'class', + 'clean_hands', + 'cleaning_services', + 'clear', + 'clear_all', + 'close', + 'close_fullscreen', + 'closed_caption', + 'closed_caption_disabled', + 'closed_caption_off', + 'cloud', + 'cloud_circle', + 'cloud_done', + 'cloud_download', + 'cloud_off', + 'cloud_queue', + 'cloud_upload', + 'code', + 'code_off', + 'coffee', + 'coffee_maker', + 'collections', + 'collections_bookmark', + 'color_lens', + 'colorize', + 'comment', + 'comment_bank', + 'commute', + 'compare', + 'compare_arrows', + 'compass_calibration', + 'compost', + 'compress', + 'computer', + 'confirmation_number', + 'connect_without_contact', + 'connected_tv', + 'construction', + 'contact_mail', + 'contact_page', + 'contact_phone', + 'contact_support', + 'contactless', + 'contacts', + 'content_copy', + 'content_cut', + 'content_paste', + 'content_paste_off', + 'control_camera', + 'control_point', + 'control_point_duplicate', + 'copy_all', + 'copyright', + 'coronavirus', + 'corporate_fare', + 'cottage', + 'countertops', + 'create', + 'create_new_folder', + 'credit_card', + 'credit_card_off', + 'credit_score', + 'crib', + 'crop', + 'crop_16_9', + 'crop_3_2', + 'crop_5_4', + 'crop_7_5', + 'crop_din', + 'crop_free', + 'crop_landscape', + 'crop_original', + 'crop_portrait', + 'crop_rotate', + 'crop_square', + 'cruelty_free', + 'dangerous', + 'dark_mode', + 'dashboard', + 'dashboard_customize', + 'data_exploration', + 'data_saver_off', + 'data_saver_on', + 'data_usage', + 'date_range', + 'deck', + 'dehaze', + 'delete', + 'delete_forever', + 'delete_outline', + 'delete_sweep', + 'delivery_dining', + 'departure_board', + 'description', + 'design_services', + 'desktop_access_disabled', + 'desktop_mac', + 'desktop_windows', + 'details', + 'developer_board', + 'developer_board_off', + 'developer_mode', + 'device_hub', + 'device_thermostat', + 'device_unknown', + 'devices', + 'devices_other', + 'dialer_sip', + 'dialpad', + 'dining', + 'dinner_dining', + 'directions', + 'directions_bike', + 'directions_boat', + 'directions_boat_filled', + 'directions_bus', + 'directions_bus_filled', + 'directions_car', + 'directions_car_filled', + 'directions_off', + 'directions_railway', + 'directions_railway_filled', + 'directions_run', + 'directions_subway', + 'directions_subway_filled', + 'directions_transit', + 'directions_transit_filled', + 'directions_walk', + 'dirty_lens', + 'disabled_by_default', + 'disabled_visible', + 'disc_full', + 'dns', + 'do_disturb', + 'do_disturb_alt', + 'do_disturb_off', + 'do_disturb_on', + 'do_not_disturb', + 'do_not_disturb_alt', + 'do_not_disturb_off', + 'do_not_disturb_on', + 'do_not_disturb_on_total_silence', + 'do_not_step', + 'do_not_touch', + 'dock', + 'document_scanner', + 'domain', + 'domain_disabled', + 'domain_verification', + 'done', + 'done_all', + 'done_outline', + 'donut_large', + 'donut_small', + 'door_back', + 'door_front', + 'door_sliding', + 'doorbell', + 'double_arrow', + 'downhill_skiing', + 'download', + 'download_done', + 'download_for_offline', + 'downloading', + 'drafts', + 'drag_handle', + 'drag_indicator', + 'draw', + 'drive_eta', + 'drive_file_move', + 'drive_file_move_rtl', + 'drive_file_rename_outline', + 'drive_folder_upload', + 'dry', + 'dry_cleaning', + 'duo', + 'dvr', + 'dynamic_feed', + 'dynamic_form', + 'e_mobiledata', + 'earbuds', + 'earbuds_battery', + 'east', + 'edgesensor_high', + 'edgesensor_low', + 'edit', + 'edit_attributes', + 'edit_calendar', + 'edit_location', + 'edit_location_alt', + 'edit_note', + 'edit_notifications', + 'edit_off', + 'edit_road', + 'eject', + 'elderly', + 'electric_bike', + 'electric_car', + 'electric_moped', + 'electric_rickshaw', + 'electric_scooter', + 'electrical_services', + 'elevator', + 'email', + 'emergency', + 'emoji_emotions', + 'emoji_events', + 'emoji_flags', + 'emoji_food_beverage', + 'emoji_nature', + 'emoji_objects', + 'emoji_people', + 'emoji_symbols', + 'emoji_transportation', + 'engineering', + 'enhanced_encryption', + 'equalizer', + 'error', + 'error_outline', + 'escalator', + 'escalator_warning', + 'euro', + 'euro_symbol', + 'ev_station', + 'event', + 'event_available', + 'event_busy', + 'event_note', + 'event_seat', + 'exit_to_app', + 'expand', + 'expand_less', + 'expand_more', + 'explicit', + 'explore', + 'explore_off', + 'exposure', + 'exposure_neg_1', + 'exposure_neg_2', + 'exposure_plus_1', + 'exposure_plus_2', + 'exposure_zero', + 'extension', + 'extension_off', + 'face', + 'face_retouching_natural', + 'face_retouching_off', + 'facebook', + 'fact_check', + 'family_restroom', + 'fast_forward', + 'fast_rewind', + 'fastfood', + 'favorite', + 'favorite_border', + 'featured_play_list', + 'featured_video', + 'feed', + 'feedback', + 'female', + 'fence', + 'festival', + 'fiber_dvr', + 'fiber_manual_record', + 'fiber_new', + 'fiber_pin', + 'fiber_smart_record', + 'file_copy', + 'file_download', + 'file_download_done', + 'file_download_off', + 'file_present', + 'file_upload', + 'filter', + 'filter_1', + 'filter_2', + 'filter_3', + 'filter_4', + 'filter_5', + 'filter_6', + 'filter_7', + 'filter_8', + 'filter_9', + 'filter_9_plus', + 'filter_alt', + 'filter_b_and_w', + 'filter_center_focus', + 'filter_drama', + 'filter_frames', + 'filter_hdr', + 'filter_list', + 'filter_none', + 'filter_tilt_shift', + 'filter_vintage', + 'find_in_page', + 'find_replace', + 'fingerprint', + 'fire_extinguisher', + 'fireplace', + 'first_page', + 'fit_screen', + 'fitness_center', + 'flag', + 'flaky', + 'flare', + 'flash_auto', + 'flash_off', + 'flash_on', + 'flashlight_off', + 'flashlight_on', + 'flatware', + 'flight', + 'flight_land', + 'flight_takeoff', + 'flip', + 'flip_camera_android', + 'flip_camera_ios', + 'flip_to_back', + 'flip_to_front', + 'flourescent', + 'flutter_dash', + 'fmd_bad', + 'fmd_good', + 'folder', + 'folder_open', + 'folder_shared', + 'folder_special', + 'follow_the_signs', + 'font_download', + 'font_download_off', + 'food_bank', + 'format_align_center', + 'format_align_justify', + 'format_align_left', + 'format_align_right', + 'format_bold', + 'format_clear', + 'format_color_fill', + 'format_color_reset', + 'format_color_text', + 'format_indent_decrease', + 'format_indent_increase', + 'format_italic', + 'format_line_spacing', + 'format_list_bulleted', + 'format_list_numbered', + 'format_list_numbered_rtl', + 'format_paint', + 'format_quote', + 'format_shapes', + 'format_size', + 'format_strikethrough', + 'format_textdirection_l_to_r', + 'format_textdirection_r_to_l', + 'format_underlined', + 'forum', + 'forward', + 'forward_10', + 'forward_30', + 'forward_5', + 'forward_to_inbox', + 'foundation', + 'free_breakfast', + 'free_cancellation', + 'front_hand', + 'fullscreen', + 'fullscreen_exit', + 'functions', + 'g_mobiledata', + 'g_translate', + 'gamepad', + 'games', + 'garage', + 'gavel', + 'generating_tokens', + 'gesture', + 'get_app', + 'gif', + 'gite', + 'golf_course', + 'gpp_bad', + 'gpp_good', + 'gpp_maybe', + 'gps_fixed', + 'gps_not_fixed', + 'gps_off', + 'grade', + 'gradient', + 'grading', + 'grain', + 'graphic_eq', + 'grass', + 'grid_3x3', + 'grid_4x4', + 'grid_goldenratio', + 'grid_off', + 'grid_on', + 'grid_view', + 'group', + 'group_add', + 'group_off', + 'group_work', + 'groups', + 'h_mobiledata', + 'h_plus_mobiledata', + 'hail', + 'handyman', + 'hardware', + 'hd', + 'hdr_auto', + 'hdr_auto_select', + 'hdr_enhanced_select', + 'hdr_off', + 'hdr_off_select', + 'hdr_on', + 'hdr_on_select', + 'hdr_plus', + 'hdr_strong', + 'hdr_weak', + 'headphones', + 'headphones_battery', + 'headset', + 'headset_mic', + 'headset_off', + 'healing', + 'health_and_safety', + 'hearing', + 'hearing_disabled', + 'height', + 'help', + 'help_center', + 'help_outline', + 'hevc', + 'hide_image', + 'hide_source', + 'high_quality', + 'highlight', + 'highlight_alt', + 'highlight_off', + 'hiking', + 'history', + 'history_edu', + 'history_toggle_off', + 'holiday_village', + 'home', + 'home_max', + 'home_mini', + 'home_repair_service', + 'home_work', + 'horizontal_distribute', + 'horizontal_rule', + 'horizontal_split', + 'hot_tub', + 'hotel', + 'hotel_class', + 'hourglass_bottom', + 'hourglass_disabled', + 'hourglass_empty', + 'hourglass_full', + 'hourglass_top', + 'house', + 'house_siding', + 'houseboat', + 'how_to_reg', + 'how_to_vote', + 'http', + 'https', + 'hvac', + 'ice_skating', + 'icecream', + 'image', + 'image_aspect_ratio', + 'image_not_supported', + 'image_search', + 'imagesearch_roller', + 'import_contacts', + 'import_export', + 'important_devices', + 'inbox', + 'incomplete_circle', + 'indeterminate_check_box', + 'info', + 'input', + 'insert_chart', + 'insert_chart_outlined', + 'insert_comment', + 'insert_drive_file', + 'insert_emoticon', + 'insert_invitation', + 'insert_link', + 'insert_photo', + 'insights', + 'integration_instructions', + 'inventory', + 'inventory_2', + 'invert_colors', + 'invert_colors_off', + 'ios_share', + 'iron', + 'iso', + 'kayaking', + 'keyboard', + 'keyboard_alt', + 'keyboard_arrow_down', + 'keyboard_arrow_left', + 'keyboard_arrow_right', + 'keyboard_arrow_up', + 'keyboard_backspace', + 'keyboard_capslock', + 'keyboard_hide', + 'keyboard_return', + 'keyboard_tab', + 'keyboard_voice', + 'king_bed', + 'kitchen', + 'kitesurfing', + 'label', + 'label_important', + 'label_off', + 'landscape', + 'language', + 'laptop', + 'laptop_chromebook', + 'laptop_mac', + 'laptop_windows', + 'last_page', + 'launch', + 'layers', + 'layers_clear', + 'leaderboard', + 'leak_add', + 'leak_remove', + 'legend_toggle', + 'lens', + 'lens_blur', + 'library_add', + 'library_add_check', + 'library_books', + 'library_music', + 'light', + 'light_mode', + 'lightbulb', + 'line_style', + 'line_weight', + 'linear_scale', + 'link', + 'link_off', + 'linked_camera', + 'liquor', + 'list', + 'list_alt', + 'live_help', + 'live_tv', + 'living', + 'local_activity', + 'local_airport', + 'local_atm', + 'local_bar', + 'local_cafe', + 'local_car_wash', + 'local_convenience_store', + 'local_dining', + 'local_drink', + 'local_fire_department', + 'local_florist', + 'local_gas_station', + 'local_grocery_store', + 'local_hospital', + 'local_hotel', + 'local_laundry_service', + 'local_library', + 'local_mall', + 'local_movies', + 'local_offer', + 'local_parking', + 'local_pharmacy', + 'local_phone', + 'local_pizza', + 'local_play', + 'local_police', + 'local_post_office', + 'local_printshop', + 'local_see', + 'local_shipping', + 'local_taxi', + 'location_city', + 'location_disabled', + 'location_off', + 'location_on', + 'location_searching', + 'lock', + 'lock_clock', + 'lock_open', + 'login', + 'logout', + 'looks', + 'looks_3', + 'looks_4', + 'looks_5', + 'looks_6', + 'looks_one', + 'looks_two', + 'loop', + 'loupe', + 'low_priority', + 'loyalty', + 'lte_mobiledata', + 'lte_plus_mobiledata', + 'luggage', + 'lunch_dining', + 'mail', + 'mail_outline', + 'male', + 'manage_accounts', + 'manage_search', + 'map', + 'maps_home_work', + 'maps_ugc', + 'margin', + 'mark_as_unread', + 'mark_chat_read', + 'mark_chat_unread', + 'mark_email_read', + 'mark_email_unread', + 'markunread', + 'markunread_mailbox', + 'masks', + 'maximize', + 'media_bluetooth_off', + 'media_bluetooth_on', + 'mediation', + 'medical_services', + 'medication', + 'meeting_room', + 'memory', + 'menu', + 'menu_book', + 'menu_open', + 'merge_type', + 'message', + 'mic', + 'mic_external_off', + 'mic_external_on', + 'mic_none', + 'mic_off', + 'microwave', + 'military_tech', + 'minimize', + 'miscellaneous_services', + 'missed_video_call', + 'mms', + 'mobile_friendly', + 'mobile_off', + 'mobile_screen_share', + 'mobiledata_off', + 'mode', + 'mode_comment', + 'mode_edit', + 'mode_edit_outline', + 'mode_night', + 'mode_standby', + 'model_training', + 'monetization_on', + 'money', + 'money_off', + 'money_off_csred', + 'monitor', + 'monitor_weight', + 'monochrome_photos', + 'mood', + 'mood_bad', + 'moped', + 'more', + 'more_horiz', + 'more_time', + 'more_vert', + 'motion_photos_auto', + 'motion_photos_off', + 'motion_photos_on', + 'motion_photos_pause', + 'motion_photos_paused', + 'mouse', + 'move_to_inbox', + 'movie', + 'movie_creation', + 'movie_filter', + 'moving', + 'mp', + 'multiline_chart', + 'multiple_stop', + 'museum', + 'music_note', + 'music_off', + 'music_video', + 'my_location', + 'nat', + 'nature', + 'nature_people', + 'navigate_before', + 'navigate_next', + 'navigation', + 'near_me', + 'near_me_disabled', + 'nearby_error', + 'nearby_off', + 'network_cell', + 'network_check', + 'network_locked', + 'network_wifi', + 'new_label', + 'new_releases', + 'next_plan', + 'next_week', + 'nfc', + 'night_shelter', + 'nightlife', + 'nightlight', + 'nightlight_round', + 'nights_stay', + 'no_accounts', + 'no_backpack', + 'no_cell', + 'no_drinks', + 'no_encryption', + 'no_encryption_gmailerrorred', + 'no_flash', + 'no_food', + 'no_luggage', + 'no_meals', + 'no_meeting_room', + 'no_photography', + 'no_sim', + 'no_stroller', + 'no_transfer', + 'nordic_walking', + 'north', + 'north_east', + 'north_west', + 'not_accessible', + 'not_interested', + 'not_listed_location', + 'not_started', + 'note', + 'note_add', + 'note_alt', + 'notes', + 'notification_add', + 'notification_important', + 'notifications', + 'notifications_active', + 'notifications_none', + 'notifications_off', + 'notifications_paused', + 'offline_bolt', + 'offline_pin', + 'offline_share', + 'ondemand_video', + 'online_prediction', + 'opacity', + 'open_in_browser', + 'open_in_full', + 'open_in_new', + 'open_in_new_off', + 'open_with', + 'other_houses', + 'outbound', + 'outbox', + 'outdoor_grill', + 'outlet', + 'outlined_flag', + 'padding', + 'pages', + 'pageview', + 'paid', + 'palette', + 'pan_tool', + 'panorama', + 'panorama_fish_eye', + 'panorama_horizontal', + 'panorama_horizontal_select', + 'panorama_photosphere', + 'panorama_photosphere_select', + 'panorama_vertical', + 'panorama_vertical_select', + 'panorama_wide_angle', + 'panorama_wide_angle_select', + 'paragliding', + 'park', + 'party_mode', + 'password', + 'pattern', + 'pause', + 'pause_circle', + 'pause_circle_filled', + 'pause_circle_outline', + 'pause_presentation', + 'payment', + 'payments', + 'pedal_bike', + 'pending', + 'pending_actions', + 'people', + 'people_alt', + 'people_outline', + 'perm_camera_mic', + 'perm_contact_calendar', + 'perm_data_setting', + 'perm_device_information', + 'perm_identity', + 'perm_media', + 'perm_phone_msg', + 'perm_scan_wifi', + 'person', + 'person_add', + 'person_add_alt', + 'person_add_alt_1', + 'person_add_disabled', + 'person_off', + 'person_outline', + 'person_pin', + 'person_pin_circle', + 'person_remove', + 'person_remove_alt_1', + 'person_search', + 'personal_injury', + 'personal_video', + 'pest_control', + 'pest_control_rodent', + 'pets', + 'phone', + 'phone_android', + 'phone_bluetooth_speaker', + 'phone_callback', + 'phone_disabled', + 'phone_enabled', + 'phone_forwarded', + 'phone_in_talk', + 'phone_iphone', + 'phone_locked', + 'phone_missed', + 'phone_paused', + 'phonelink', + 'phonelink_erase', + 'phonelink_lock', + 'phonelink_off', + 'phonelink_ring', + 'phonelink_setup', + 'photo', + 'photo_album', + 'photo_camera', + 'photo_camera_back', + 'photo_camera_front', + 'photo_filter', + 'photo_library', + 'photo_size_select_actual', + 'photo_size_select_large', + 'photo_size_select_small', + 'piano', + 'piano_off', + 'picture_as_pdf', + 'picture_in_picture', + 'picture_in_picture_alt', + 'pie_chart', + 'pie_chart_outline', + 'pin', + 'pin_drop', + 'pin_end', + 'pin_invoke', + 'pivot_table_chart', + 'place', + 'plagiarism', + 'play_arrow', + 'play_circle', + 'play_circle_filled', + 'play_circle_outline', + 'play_disabled', + 'play_for_work', + 'play_lesson', + 'playlist_add', + 'playlist_add_check', + 'playlist_play', + 'plumbing', + 'plus_one', + 'podcasts', + 'point_of_sale', + 'policy', + 'poll', + 'polymer', + 'pool', + 'portable_wifi_off', + 'portrait', + 'post_add', + 'power', + 'power_input', + 'power_off', + 'power_settings_new', + 'precision_manufacturing', + 'pregnant_woman', + 'present_to_all', + 'preview', + 'price_change', + 'price_check', + 'print', + 'print_disabled', + 'priority_high', + 'privacy_tip', + 'private_connectivity', + 'production_quantity_limits', + 'psychology', + 'public', + 'public_off', + 'publish', + 'published_with_changes', + 'push_pin', + 'qr_code', + 'qr_code_2', + 'qr_code_scanner', + 'query_builder', + 'query_stats', + 'question_answer', + 'queue', + 'queue_music', + 'queue_play_next', + 'quickreply', + 'quiz', + 'r_mobiledata', + 'radar', + 'radio', + 'radio_button_checked', + 'radio_button_unchecked', + 'railway_alert', + 'ramen_dining', + 'rate_review', + 'raw_off', + 'raw_on', + 'read_more', + 'real_estate_agent', + 'receipt', + 'receipt_long', + 'recent_actors', + 'recommend', + 'record_voice_over', + 'recycling', + 'redeem', + 'redo', + 'reduce_capacity', + 'refresh', + 'remember_me', + 'remove', + 'remove_circle', + 'remove_circle_outline', + 'remove_done', + 'remove_from_queue', + 'remove_moderator', + 'remove_red_eye', + 'remove_shopping_cart', + 'reorder', + 'repeat', + 'repeat_on', + 'repeat_one', + 'repeat_one_on', + 'replay', + 'replay_10', + 'replay_30', + 'replay_5', + 'replay_circle_filled', + 'reply', + 'reply_all', + 'report', + 'report_gmailerrorred', + 'report_off', + 'report_problem', + 'request_page', + 'request_quote', + 'reset_tv', + 'restart_alt', + 'restaurant', + 'restaurant_menu', + 'restore', + 'restore_from_trash', + 'restore_page', + 'reviews', + 'rice_bowl', + 'ring_volume', + 'roofing', + 'room', + 'room_preferences', + 'room_service', + 'rotate_90_degrees_ccw', + 'rotate_left', + 'rotate_right', + 'rounded_corner', + 'router', + 'rowing', + 'rss_feed', + 'rsvp', + 'rtt', + 'rule', + 'rule_folder', + 'run_circle', + 'running_with_errors', + 'rv_hookup', + 'safety_divider', + 'sailing', + 'sanitizer', + 'satellite', + 'save', + 'save_alt', + 'saved_search', + 'savings', + 'scanner', + 'scatter_plot', + 'schedule', + 'schedule_send', + 'schema', + 'school', + 'science', + 'score', + 'screen_lock_landscape', + 'screen_lock_portrait', + 'screen_lock_rotation', + 'screen_rotation', + 'screen_search_desktop', + 'screen_share', + 'screenshot', + 'sd', + 'sd_card', + 'sd_card_alert', + 'sd_storage', + 'search', + 'search_off', + 'security', + 'security_update', + 'security_update_good', + 'security_update_warning', + 'segment', + 'select_all', + 'self_improvement', + 'sell', + 'send', + 'send_and_archive', + 'send_to_mobile', + 'sensor_door', + 'sensor_window', + 'sensors', + 'sensors_off', + 'sentiment_dissatisfied', + 'sentiment_neutral', + 'sentiment_satisfied', + 'sentiment_satisfied_alt', + 'sentiment_very_dissatisfied', + 'sentiment_very_satisfied', + 'set_meal', + 'settings', + 'settings_accessibility', + 'settings_applications', + 'settings_backup_restore', + 'settings_bluetooth', + 'settings_brightness', + 'settings_cell', + 'settings_ethernet', + 'settings_input_antenna', + 'settings_input_component', + 'settings_input_composite', + 'settings_input_hdmi', + 'settings_input_svideo', + 'settings_overscan', + 'settings_phone', + 'settings_power', + 'settings_remote', + 'settings_suggest', + 'settings_system_daydream', + 'settings_voice', + 'share', + 'share_location', + 'shield', + 'shop', + 'shop_2', + 'shop_two', + 'shopping_bag', + 'shopping_basket', + 'shopping_cart', + 'short_text', + 'shortcut', + 'show_chart', + 'shower', + 'shuffle', + 'shuffle_on', + 'shutter_speed', + 'sick', + 'signal_cellular_0_bar', + 'signal_cellular_4_bar', + 'signal_cellular_alt', + 'signal_cellular_connected_no_internet_0_bar', + 'signal_cellular_connected_no_internet_4_bar', + 'signal_cellular_no_sim', + 'signal_cellular_nodata', + 'signal_cellular_null', + 'signal_cellular_off', + 'signal_wifi_0_bar', + 'signal_wifi_4_bar', + 'signal_wifi_4_bar_lock', + 'signal_wifi_bad', + 'signal_wifi_connected_no_internet_4', + 'signal_wifi_off', + 'signal_wifi_statusbar_4_bar', + 'signal_wifi_statusbar_connected_no_internet_4', + 'signal_wifi_statusbar_null', + 'sim_card', + 'sim_card_alert', + 'sim_card_download', + 'single_bed', + 'sip', + 'skateboarding', + 'skip_next', + 'skip_previous', + 'sledding', + 'slideshow', + 'slow_motion_video', + 'smart_button', + 'smart_display', + 'smart_screen', + 'smart_toy', + 'smartphone', + 'smoke_free', + 'smoking_rooms', + 'sms', + 'sms_failed', + 'snippet_folder', + 'snooze', + 'snowboarding', + 'snowmobile', + 'snowshoeing', + 'soap', + 'social_distance', + 'sort', + 'sort_by_alpha', + 'source', + 'south', + 'south_east', + 'south_west', + 'spa', + 'space_bar', + 'space_dashboard', + 'speaker', + 'speaker_group', + 'speaker_notes', + 'speaker_notes_off', + 'speaker_phone', + 'speed', + 'spellcheck', + 'splitscreen', + 'sports', + 'sports_bar', + 'sports_baseball', + 'sports_basketball', + 'sports_cricket', + 'sports_esports', + 'sports_football', + 'sports_golf', + 'sports_handball', + 'sports_hockey', + 'sports_kabaddi', + 'sports_mma', + 'sports_motorsports', + 'sports_rugby', + 'sports_score', + 'sports_soccer', + 'sports_tennis', + 'sports_volleyball', + 'square_foot', + 'stacked_bar_chart', + 'stacked_line_chart', + 'stairs', + 'star', + 'star_border', + 'star_border_purple500', + 'star_half', + 'star_outline', + 'star_purple500', + 'star_rate', + 'stars', + 'stay_current_landscape', + 'stay_current_portrait', + 'stay_primary_landscape', + 'stay_primary_portrait', + 'sticky_note_2', + 'stop', + 'stop_circle', + 'stop_screen_share', + 'storage', + 'store', + 'store_mall_directory', + 'storefront', + 'storm', + 'straighten', + 'stream', + 'streetview', + 'strikethrough_s', + 'stroller', + 'style', + 'subdirectory_arrow_left', + 'subdirectory_arrow_right', + 'subject', + 'subscript', + 'subscriptions', + 'subtitles', + 'subtitles_off', + 'subway', + 'summarize', + 'superscript', + 'supervised_user_circle', + 'supervisor_account', + 'support', + 'support_agent', + 'surfing', + 'surround_sound', + 'swap_calls', + 'swap_horiz', + 'swap_horizontal_circle', + 'swap_vert', + 'swap_vertical_circle', + 'swipe', + 'switch_account', + 'switch_camera', + 'switch_left', + 'switch_right', + 'switch_video', + 'sync', + 'sync_alt', + 'sync_disabled', + 'sync_problem', + 'system_security_update', + 'system_security_update_good', + 'system_security_update_warning', + 'system_update', + 'system_update_alt', + 'tab', + 'tab_unselected', + 'table_chart', + 'table_rows', + 'table_view', + 'tablet', + 'tablet_android', + 'tablet_mac', + 'tag', + 'tag_faces', + 'takeout_dining', + 'tap_and_play', + 'tapas', + 'task', + 'task_alt', + 'taxi_alert', + 'terrain', + 'text_fields', + 'text_format', + 'text_rotate_up', + 'text_rotate_vertical', + 'text_rotation_angledown', + 'text_rotation_angleup', + 'text_rotation_down', + 'text_rotation_none', + 'text_snippet', + 'textsms', + 'texture', + 'theater_comedy', + 'theaters', + 'thermostat', + 'thermostat_auto', + 'thumb_down', + 'thumb_down_alt', + 'thumb_down_off_alt', + 'thumb_up', + 'thumb_up_alt', + 'thumb_up_off_alt', + 'thumbs_up_down', + 'time_to_leave', + 'timelapse', + 'timeline', + 'timer', + 'timer_10', + 'timer_10_select', + 'timer_3', + 'timer_3_select', + 'timer_off', + 'tips_and_updates', + 'title', + 'toc', + 'today', + 'toggle_off', + 'toggle_on', + 'toll', + 'tonality', + 'topic', + 'touch_app', + 'tour', + 'toys', + 'track_changes', + 'traffic', + 'train', + 'tram', + 'transfer_within_a_station', + 'transform', + 'transgender', + 'transit_enterexit', + 'translate', + 'travel_explore', + 'trending_down', + 'trending_flat', + 'trending_up', + 'trip_origin', + 'try', + 'tty', + 'tune', + 'tungsten', + 'turned_in', + 'turned_in_not', + 'tv', + 'tv_off', + 'two_wheeler', + 'umbrella', + 'unarchive', + 'undo', + 'unfold_less', + 'unfold_more', + 'unpublished', + 'unsubscribe', + 'upcoming', + 'update', + 'update_disabled', + 'upgrade', + 'upload', + 'upload_file', + 'usb', + 'usb_off', + 'verified', + 'verified_user', + 'vertical_align_bottom', + 'vertical_align_center', + 'vertical_align_top', + 'vertical_distribute', + 'vertical_split', + 'vibration', + 'video_call', + 'video_camera_back', + 'video_camera_front', + 'video_label', + 'video_library', + 'video_settings', + 'video_stable', + 'videocam', + 'videocam_off', + 'videogame_asset', + 'videogame_asset_off', + 'view_agenda', + 'view_array', + 'view_carousel', + 'view_column', + 'view_comfy', + 'view_compact', + 'view_day', + 'view_headline', + 'view_in_ar', + 'view_list', + 'view_module', + 'view_quilt', + 'view_sidebar', + 'view_stream', + 'view_week', + 'vignette', + 'villa', + 'visibility', + 'visibility_off', + 'voice_chat', + 'voice_over_off', + 'voicemail', + 'volume_down', + 'volume_mute', + 'volume_off', + 'volume_up', + 'volunteer_activism', + 'vpn_key', + 'vpn_lock', + 'vrpano', + 'wallpaper', + 'warning', + 'warning_amber', + 'wash', + 'watch', + 'watch_later', + 'water', + 'water_damage', + 'water_drop', + 'waterfall_chart', + 'waves', + 'waving_hand', + 'wb_auto', + 'wb_cloudy', + 'wb_incandescent', + 'wb_iridescent', + 'wb_shade', + 'wb_sunny', + 'wb_twilight', + 'wc', + 'web', + 'web_asset', + 'web_asset_off', + 'weekend', + 'west', + 'whatshot', + 'wheelchair_pickup', + 'where_to_vote', + 'widgets', + 'wifi', + 'wifi_calling', + 'wifi_calling_3', + 'wifi_lock', + 'wifi_off', + 'wifi_protected_setup', + 'wifi_tethering', + 'wifi_tethering_error_rounded', + 'wifi_tethering_off', + 'window', + 'wine_bar', + 'work', + 'work_off', + 'work_outline', + 'workspaces', + 'wrap_text', + 'wrong_location', + 'wysiwyg', + 'yard', + 'youtube_searched_for', + 'zoom_in', + 'zoom_out', + 'zoom_out_map', +]; +export const feather = [ + 'activity', + 'airplay', + 'alert-circle', + 'alert-octagon', + 'alert-triangle', + 'align-center', + 'align-justify', + 'align-left', + 'align-right', + 'anchor', + 'aperture', + 'archive', + 'arrow-down-circle', + 'arrow-down-left', + 'arrow-down-right', + 'arrow-down', + 'arrow-left-circle', + 'arrow-left', + 'arrow-right-circle', + 'arrow-right', + 'arrow-up-circle', + 'arrow-up-left', + 'arrow-up-right', + 'arrow-up', + 'at-sign', + 'award', + 'bar-chart-2', + 'bar-chart', + 'battery-charging', + 'battery', + 'bell-off', + 'bell', + 'bluetooth', + 'bold', + 'book-open', + 'book', + 'bookmark', + 'box', + 'briefcase', + 'calendar', + 'camera-off', + 'camera', + 'cast', + 'check-circle', + 'check-square', + 'check', + 'chevron-down', + 'chevron-left', + 'chevron-right', + 'chevron-up', + 'chevrons-down', + 'chevrons-left', + 'chevrons-right', + 'chevrons-up', + 'chrome', + 'circle', + 'clipboard', + 'clock', + 'cloud-drizzle', + 'cloud-lightning', + 'cloud-off', + 'cloud-rain', + 'cloud-snow', + 'cloud', + 'code', + 'codepen', + 'codesandbox', + 'coffee', + 'columns', + 'command', + 'compass', + 'copy', + 'corner-down-left', + 'corner-down-right', + 'corner-left-down', + 'corner-left-up', + 'corner-right-down', + 'corner-right-up', + 'corner-up-left', + 'corner-up-right', + 'cpu', + 'credit-card', + 'crop', + 'crosshair', + 'database', + 'delete', + 'disc', + 'dollar-sign', + 'download-cloud', + 'download', + 'droplet', + 'edit-2', + 'edit-3', + 'edit', + 'external-link', + 'eye-off', + 'eye', + 'facebook', + 'fast-forward', + 'feather', + 'figma', + 'file-minus', + 'file-plus', + 'file-text', + 'file', + 'film', + 'filter', + 'flag', + 'folder-minus', + 'folder-plus', + 'folder', + 'framer', + 'frown', + 'gift', + 'git-branch', + 'git-commit', + 'git-merge', + 'git-pull-request', + 'github', + 'gitlab', + 'globe', + 'grid', + 'hard-drive', + 'hash', + 'headphones', + 'heart', + 'help-circle', + 'hexagon', + 'home', + 'image', + 'inbox', + 'info', + 'instagram', + 'italic', + 'key', + 'layers', + 'layout', + 'life-buoy', + 'link-2', + 'link', + 'linkedin', + 'list', + 'loader', + 'lock', + 'log-in', + 'log-out', + 'mail', + 'map-pin', + 'map', + 'maximize-2', + 'maximize', + 'meh', + 'menu', + 'message-circle', + 'message-square', + 'mic-off', + 'mic', + 'minimize-2', + 'minimize', + 'minus-circle', + 'minus-square', + 'minus', + 'monitor', + 'moon', + 'more-horizontal', + 'more-vertical', + 'mouse-pointer', + 'move', + 'music', + 'navigation-2', + 'navigation', + 'octagon', + 'package', + 'paperclip', + 'pause-circle', + 'pause', + 'pen-tool', + 'percent', + 'phone-call', + 'phone-forwarded', + 'phone-incoming', + 'phone-missed', + 'phone-off', + 'phone-outgoing', + 'phone', + 'pie-chart', + 'play-circle', + 'play', + 'plus-circle', + 'plus-square', + 'plus', + 'pocket', + 'power', + 'printer', + 'radio', + 'refresh-ccw', + 'refresh-cw', + 'repeat', + 'rewind', + 'rotate-ccw', + 'rotate-cw', + 'rss', + 'save', + 'scissors', + 'search', + 'send', + 'server', + 'settings', + 'share-2', + 'share', + 'shield-off', + 'shield', + 'shopping-bag', + 'shopping-cart', + 'shuffle', + 'sidebar', + 'skip-back', + 'skip-forward', + 'slack', + 'slash', + 'sliders', + 'smartphone', + 'smile', + 'speaker', + 'square', + 'star', + 'stop-circle', + 'sun', + 'sunrise', + 'sunset', + 'tablet', + 'tag', + 'target', + 'terminal', + 'thermometer', + 'thumbs-down', + 'thumbs-up', + 'toggle-left', + 'toggle-right', + 'tool', + 'trash-2', + 'trash', + 'trello', + 'trending-down', + 'trending-up', + 'triangle', + 'truck', + 'tv', + 'twitch', + 'twitter', + 'type', + 'umbrella', + 'underline', + 'unlock', + 'upload-cloud', + 'upload', + 'user-check', + 'user-minus', + 'user-plus', + 'user-x', + 'user', + 'users', + 'video-off', + 'video', + 'voicemail', + 'volume-1', + 'volume-2', + 'volume-x', + 'volume', + 'watch', + 'wifi-off', + 'wifi', + 'wind', + 'x-circle', + 'x-octagon', + 'x-square', + 'x', + 'youtube', + 'zap-off', + 'zap', + 'zoom-in', + 'zoom-out', +]; +// heroicons v2.0.18 - 292 icons +export const heroicons = [ + 'academic-cap', + 'archive-box-arrow-down', + 'adjustments-vertical', + 'archive-box', + 'arrow-down-circle', + 'archive-box-x-mark', + 'adjustments-horizontal', + 'arrow-down-left', + 'arrow-down-on-square', + 'arrow-down-on-square-stack', + 'arrow-down', + 'arrow-down-right', + 'arrow-left', + 'arrow-left-circle', + 'arrow-down-tray', + 'arrow-long-right', + 'arrow-long-down', + 'arrow-left-on-rectangle', + 'arrow-path', + 'arrow-long-up', + 'arrow-right-circle', + 'arrow-right-on-rectangle', + 'arrow-right', + 'arrow-small-down', + 'arrow-path-rounded-square', + 'arrow-long-left', + 'arrow-small-left', + 'arrow-trending-down', + 'arrow-small-up', + 'arrow-up-left', + 'arrow-trending-up', + 'arrow-up-circle', + 'arrow-up-on-square-stack', + 'arrow-up-on-square', + 'arrow-up-right', + 'arrow-up-tray', + 'arrow-up', + 'arrow-uturn-right', + 'arrow-uturn-up', + 'arrow-top-right-on-square', + 'arrow-uturn-down', + 'arrows-pointing-out', + 'arrow-uturn-left', + 'arrows-pointing-in', + 'arrows-up-down', + 'at-symbol', + 'backspace', + 'backward', + 'banknotes', + 'arrows-right-left', + 'bars-2', + 'bars-3-bottom-left', + 'bars-3-center-left', + 'bars-3', + 'bars-arrow-down', + 'bars-4', + 'bars-arrow-up', + 'battery-0', + 'bars-3-bottom-right', + 'battery-100', + 'bell-alert', + 'bell-slash', + 'battery-50', + 'arrow-small-right', + 'beaker', + 'bell', + 'bolt', + 'bookmark-slash', + 'book-open', + 'bookmark-square', + 'bolt-slash', + 'bookmark', + 'briefcase', + 'building-library', + 'bell-snooze', + 'building-office-2', + 'building-storefront', + 'building-office', + 'calculator', + 'cake', + 'calendar-days', + 'chart-bar-square', + 'chart-bar', + 'camera', + 'bug-ant', + 'calendar', + 'chat-bubble-bottom-center', + 'chart-pie', + 'chat-bubble-left-right', + 'chat-bubble-left-ellipsis', + 'chat-bubble-bottom-center-text', + 'check-circle', + 'check-badge', + 'chat-bubble-oval-left', + 'chat-bubble-left', + 'check', + 'chat-bubble-oval-left-ellipsis', + 'chevron-double-right', + 'chevron-down', + 'chevron-double-down', + 'chevron-double-up', + 'circle-stack', + 'chevron-up-down', + 'chevron-up', + 'clipboard-document-list', + 'chevron-double-left', + 'chevron-right', + 'chevron-left', + 'cloud-arrow-down', + 'cloud-arrow-up', + 'cloud', + 'code-bracket-square', + 'code-bracket', + 'cog-6-tooth', + 'clipboard-document', + 'clock', + 'clipboard-document-check', + 'cog-8-tooth', + 'cog', + 'command-line', + 'computer-desktop', + 'cube-transparent', + 'cpu-chip', + 'credit-card', + 'cube', + 'currency-dollar', + 'currency-bangladeshi', + 'currency-euro', + 'currency-pound', + 'currency-yen', + 'currency-rupee', + 'cursor-arrow-ripple', + 'device-phone-mobile', + 'device-tablet', + 'document-arrow-down', + 'cursor-arrow-rays', + 'document-check', + 'document-chart-bar', + 'document-duplicate', + 'document-minus', + 'clipboard', + 'document-magnifying-glass', + 'document-plus', + 'document', + 'document-text', + 'ellipsis-horizontal-circle', + 'document-arrow-up', + 'ellipsis-horizontal', + 'ellipsis-vertical', + 'eye-dropper', + 'exclamation-triangle', + 'eye-slash', + 'eye', + 'exclamation-circle', + 'envelope-open', + 'face-smile', + 'film', + 'flag', + 'folder-arrow-down', + 'envelope', + 'fire', + 'folder-minus', + 'folder-open', + 'face-frown', + 'folder-plus', + 'forward', + 'funnel', + 'gift-top', + 'folder', + 'gif', + 'globe-alt', + 'finger-print', + 'globe-asia-australia', + 'globe-europe-africa', + 'hand-raised', + 'gift', + 'home', + 'identification', + 'globe-americas', + 'hashtag', + 'inbox-arrow-down', + 'inbox-stack', + 'information-circle', + 'inbox', + 'key', + 'lifebuoy', + 'hand-thumb-down', + 'language', + 'hand-thumb-up', + 'heart', + 'home-modern', + 'light-bulb', + 'lock-closed', + 'magnifying-glass-plus', + 'magnifying-glass', + 'lock-open', + 'magnifying-glass-circle', + 'link', + 'list-bullet', + 'map', + 'map-pin', + 'megaphone', + 'magnifying-glass-minus', + 'minus-circle', + 'musical-note', + 'paint-brush', + 'newspaper', + 'no-symbol', + 'minus-small', + 'paper-airplane', + 'minus', + 'microphone', + 'moon', + 'paper-clip', + 'pause', + 'phone-arrow-up-right', + 'phone-arrow-down-left', + 'phone-x-mark', + 'phone', + 'pencil', + 'play-pause', + 'photo', + 'pencil-square', + 'play', + 'plus-small', + 'plus', + 'power', + 'play-circle', + 'presentation-chart-line', + 'pause-circle', + 'presentation-chart-bar', + 'printer', + 'question-mark-circle', + 'qr-code', + 'queue-list', + 'receipt-percent', + 'radio', + 'receipt-refund', + 'plus-circle', + 'rectangle-group', + 'puzzle-piece', + 'rocket-launch', + 'rectangle-stack', + 'server', + 'rss', + 'scale', + 'server-stack', + 'share', + 'shield-exclamation', + 'shopping-cart', + 'shopping-bag', + 'signal-slash', + 'signal', + 'scissors', + 'shield-check', + 'speaker-wave', + 'speaker-x-mark', + 'squares-plus', + 'star', + 'stop-circle', + 'sun', + 'sparkles', + 'squares-2x2', + 'square-2-stack', + 'square-3-stack-3d', + 'table-cells', + 'ticket', + 'swatch', + 'tag', + 'tv', + 'user-plus', + 'user-minus', + 'stop', + 'user', + 'truck', + 'users', + 'video-camera-slash', + 'user-circle', + 'video-camera', + 'user-group', + 'trophy', + 'viewfinder-circle', + 'variable', + 'trash', + 'view-columns', + 'wifi', + 'window', + 'wrench-screwdriver', + 'wrench', + 'x-mark', + 'wallet', + 'x-circle', +]; diff --git a/frontend/src/app/code/code.component.html b/frontend/src/app/modules/actions/actions.component.html similarity index 73% rename from frontend/src/app/code/code.component.html rename to frontend/src/app/modules/actions/actions.component.html index 1dc6b368..cbed5be7 100644 --- a/frontend/src/app/code/code.component.html +++ b/frontend/src/app/modules/actions/actions.component.html @@ -1,7 +1,22 @@ +
+ + +
+
+ +
+

+ Actions +

+
+
+
+ - - Code Operations -
@@ -46,3 +61,4 @@
{{ result }}
+
\ No newline at end of file diff --git a/frontend/src/app/code/code.component.scss b/frontend/src/app/modules/actions/actions.component.scss similarity index 100% rename from frontend/src/app/code/code.component.scss rename to frontend/src/app/modules/actions/actions.component.scss diff --git a/frontend/src/app/modules/actions/actions.component.spec.ts b/frontend/src/app/modules/actions/actions.component.spec.ts new file mode 100644 index 00000000..ee4b368c --- /dev/null +++ b/frontend/src/app/modules/actions/actions.component.spec.ts @@ -0,0 +1,121 @@ +// import { ComponentFixture, TestBed } from '@angular/core/testing'; +// import { ReactiveFormsModule } from '@angular/forms'; +// import { MaterialModule } from '@app/material.module'; +// import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +// import { ActionsComponent } from './actions.component'; +// import { CodeService } from '@app/shared/services/code.service'; +// import { of, throwError } from 'rxjs'; +// +// describe.skip('ActionsComponent', () => { +// let component: ActionsComponent; +// let fixture: ComponentFixture; +// let codeService: jest.Mocked; +// +// beforeEach(async () => { +// const codeServiceMock = { +// runCodebaseQuery: jest.fn(), +// getRepositories: jest.fn(), +// runCodeEditWorkflow: jest.fn(), +// selectFilesToEdit: jest.fn(), +// }; +// +// await TestBed.configureTestingModule({ +// declarations: [ActionsComponent], +// imports: [ReactiveFormsModule, MaterialModule, NoopAnimationsModule], +// providers: [{ provide: CodeService, useValue: codeServiceMock }], +// }).compileComponents(); +// +// codeService = TestBed.inject(CodeService) as jest.Mocked; +// }); +// +// beforeEach(() => { +// fixture = TestBed.createComponent(ActionsComponent); +// component = fixture.componentInstance; +// codeService.getRepositories.mockReturnValue(of(['repo1', 'repo2'])); +// fixture.detectChanges(); +// }); +// +// it('should create', () => { +// expect(component).toBeTruthy(); +// }); +// +// it('should execute codebase query operation and update result', () => { +// component.codeForm.setValue({ +// workingDirectory: 'repo1', +// operationType: 'query', +// input: 'test query', +// }); +// +// codeService.runCodebaseQuery.mockReturnValue(of({ response: 'Query result' })); +// +// component.onSubmit(); +// +// expect(codeService.runCodebaseQuery).toHaveBeenCalledWith('repo1', 'test query'); +// expect(component.result).toBe('Query result'); +// expect(component.isLoading).toBeFalsy(); +// }); +// +// it('should execute code edit workflow operation and update result', () => { +// component.codeForm.setValue({ +// workingDirectory: 'repo1', +// operationType: 'code', +// input: 'edit requirements', +// }); +// +// const mockResponse = { changes: ['file1.ts', 'file2.ts'] }; +// codeService.runCodeEditWorkflow.mockReturnValue(of(mockResponse)); +// +// component.onSubmit(); +// +// expect(codeService.runCodeEditWorkflow).toHaveBeenCalledWith('repo1', 'edit requirements'); +// expect(component.result).toBe(JSON.stringify(mockResponse, null, 2)); +// expect(component.isLoading).toBeFalsy(); +// }); +// +// it('should execute select files operation and update result', () => { +// component.codeForm.setValue({ +// workingDirectory: 'repo1', +// operationType: 'selectFiles', +// input: 'selection criteria', +// }); +// +// const mockResponse = { selectedFiles: ['file1.ts', 'file2.ts'] }; +// codeService.selectFilesToEdit.mockReturnValue(of(mockResponse)); +// +// component.onSubmit(); +// +// expect(codeService.selectFilesToEdit).toHaveBeenCalledWith('repo1', 'selection criteria'); +// expect(component.result).toBe(JSON.stringify(mockResponse, null, 2)); +// expect(component.isLoading).toBeFalsy(); +// }); +// +// it('should handle errors during operation execution', () => { +// component.codeForm.setValue({ +// workingDirectory: 'repo1', +// operationType: 'query', +// input: 'test query', +// }); +// +// const errorMessage = 'API Error'; +// codeService.runCodebaseQuery.mockReturnValue(throwError(() => new Error(errorMessage))); +// +// component.onSubmit(); +// +// expect(codeService.runCodebaseQuery).toHaveBeenCalledWith('repo1', 'test query'); +// expect(component.result).toBe(`Error during query operation: ${errorMessage}`); +// expect(component.isLoading).toBeFalsy(); +// }); +// +// it('should handle invalid operation type', () => { +// component.codeForm.setValue({ +// workingDirectory: 'repo1', +// operationType: 'invalidType', +// input: 'test input', +// }); +// +// component.onSubmit(); +// +// expect(component.result).toBe('Error: Invalid operation type'); +// expect(component.isLoading).toBeFalsy(); +// }); +// }); diff --git a/frontend/src/app/code/code.component.ts b/frontend/src/app/modules/actions/actions.component.ts similarity index 65% rename from frontend/src/app/code/code.component.ts rename to frontend/src/app/modules/actions/actions.component.ts index f2a137cd..2d2236e7 100644 --- a/frontend/src/app/code/code.component.ts +++ b/frontend/src/app/modules/actions/actions.component.ts @@ -1,20 +1,39 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormGroup, Validators } from '@angular/forms'; -import { CodeService } from '@app/shared/services/code.service'; +import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; import { Observable } from 'rxjs'; +import { CommonModule } from "@angular/common"; +import { RouterModule } from "@angular/router"; +import { MatFormFieldModule } from "@angular/material/form-field"; +import { MatSelectModule } from "@angular/material/select"; +import { MatCardModule } from "@angular/material/card"; +import { MatProgressBarModule } from "@angular/material/progress-bar"; +import { MatInputModule } from '@angular/material/input'; +import { ActionsService } from "./actions.service"; +import {MatIconModule} from "@angular/material/icon"; @Component({ selector: 'app-code', - templateUrl: './code.component.html', - styleUrls: ['./code.component.scss'], + templateUrl: './actions.component.html', + styleUrls: ['./actions.component.scss'], + standalone: true, + imports: [ + CommonModule, + ReactiveFormsModule, + MatFormFieldModule, + MatSelectModule, + MatIconModule, + MatCardModule, + MatProgressBarModule, + MatInputModule + ] }) -export class CodeComponent implements OnInit { +export class ActionsComponent implements OnInit { codeForm!: FormGroup; result: string = ''; isLoading: boolean = false; repositories: string[] = []; - constructor(private fb: FormBuilder, private codeService: CodeService) {} + constructor(private fb: FormBuilder, private actionsService: ActionsService) {} ngOnInit() { this.codeForm = this.fb.group({ @@ -23,7 +42,7 @@ export class CodeComponent implements OnInit { input: ['', Validators.required], }); - this.codeService.getRepositories().subscribe({ + this.actionsService.getRepositories().subscribe({ next: (repos: string[]) => { this.repositories = repos; if (repos.length > 0) { @@ -71,13 +90,13 @@ export class CodeComponent implements OnInit { switch (operationType) { case 'code': - operation = this.codeService.runCodeEditWorkflow(workingDirectory, input); + operation = this.actionsService.runCodeEditWorkflow(workingDirectory, input); break; case 'query': - operation = this.codeService.runCodebaseQuery(workingDirectory, input); + operation = this.actionsService.runCodebaseQuery(workingDirectory, input); break; case 'selectFiles': - operation = this.codeService.selectFilesToEdit(workingDirectory, input); + operation = this.actionsService.selectFilesToEdit(workingDirectory, input); break; default: this.result = 'Error: Invalid operation type'; diff --git a/frontend/src/app/modules/actions/actions.routes.ts b/frontend/src/app/modules/actions/actions.routes.ts new file mode 100644 index 00000000..141641ca --- /dev/null +++ b/frontend/src/app/modules/actions/actions.routes.ts @@ -0,0 +1,9 @@ +import { Routes } from '@angular/router'; +import {ActionsComponent} from "./actions.component"; + +export default [ + { + path: '', + component: ActionsComponent, + }, +] as Routes; diff --git a/frontend/src/app/shared/services/code.service.ts b/frontend/src/app/modules/actions/actions.service.ts similarity index 61% rename from frontend/src/app/shared/services/code.service.ts rename to frontend/src/app/modules/actions/actions.service.ts index b2d9cdbf..0a3d1b54 100644 --- a/frontend/src/app/shared/services/code.service.ts +++ b/frontend/src/app/modules/actions/actions.service.ts @@ -1,28 +1,29 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; -import { environment } from '@env/environment'; -import { Data } from '@shared'; +import {environment} from "../../../environments/environment"; + + @Injectable({ providedIn: 'root', }) -export class CodeService { +export class ActionsService { constructor(private http: HttpClient) {} runCodeEditWorkflow(workingDirectory: string, requirements: string): Observable { - return this.http.post(`${environment.serverUrl}/code/edit`, { workingDirectory, requirements }); + return this.http.post(`${environment.apiBaseUrl}code/edit`, { workingDirectory, requirements }); } runCodebaseQuery(workingDirectory: string, query: string): Observable<{ response: string }> { - return this.http.post<{ response: string }>(`${environment.serverUrl}/code/query`, { workingDirectory, query }); + return this.http.post<{ response: string }>(`${environment.apiBaseUrl}code/query`, { workingDirectory, query }); } selectFilesToEdit(workingDirectory: string, requirements: string): Observable { - return this.http.post(`${environment.serverUrl}/code/select-files`, { workingDirectory, requirements }); + return this.http.post(`${environment.apiBaseUrl}code/select-files`, { workingDirectory, requirements }); } getRepositories(): Observable { - return this.http.get(`${environment.serverUrl}/code/repositories`); + return this.http.get(`${environment.apiBaseUrl}code/repositories`); } } diff --git a/frontend/src/app/modules/admin/apps/chat/chat-info/chat-info.component.html b/frontend/src/app/modules/admin/apps/chat/chat-info/chat-info.component.html new file mode 100644 index 00000000..b663394a --- /dev/null +++ b/frontend/src/app/modules/admin/apps/chat/chat-info/chat-info.component.html @@ -0,0 +1,73 @@ +
+ +
+ +
Chat info
+
+ +
+
+ + +
+
+
diff --git a/frontend/src/app/modules/admin/apps/chat/chat-info/chat-info.component.ts b/frontend/src/app/modules/admin/apps/chat/chat-info/chat-info.component.ts new file mode 100644 index 00000000..d50b88ba --- /dev/null +++ b/frontend/src/app/modules/admin/apps/chat/chat-info/chat-info.component.ts @@ -0,0 +1,28 @@ +import { + ChangeDetectionStrategy, + Component, + Input, + ViewEncapsulation, +} from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatDrawer } from '@angular/material/sidenav'; +import { Chat } from 'app/modules/admin/apps/chat/chat.types'; + +@Component({ + selector: 'chat-info', + templateUrl: './chat-info.component.html', + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [MatButtonModule, MatIconModule], +}) +export class ChatInfoComponent { + @Input() chat: Chat; + @Input() drawer: MatDrawer; + + /** + * Constructor + */ + constructor() {} +} diff --git a/frontend/src/app/modules/admin/apps/chat/chat.component.html b/frontend/src/app/modules/admin/apps/chat/chat.component.html new file mode 100644 index 00000000..9c7107f0 --- /dev/null +++ b/frontend/src/app/modules/admin/apps/chat/chat.component.html @@ -0,0 +1,6 @@ +
+ +
+ +
+
diff --git a/frontend/src/app/modules/admin/apps/chat/chat.component.ts b/frontend/src/app/modules/admin/apps/chat/chat.component.ts new file mode 100644 index 00000000..13e91170 --- /dev/null +++ b/frontend/src/app/modules/admin/apps/chat/chat.component.ts @@ -0,0 +1,21 @@ +import { + ChangeDetectionStrategy, + Component, + ViewEncapsulation, +} from '@angular/core'; +import { RouterOutlet } from '@angular/router'; + +@Component({ + selector: 'chat', + templateUrl: './chat.component.html', + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [RouterOutlet], +}) +export class ChatComponent { + /** + * Constructor + */ + constructor() {} +} diff --git a/frontend/src/app/modules/admin/apps/chat/chat.routes.ts b/frontend/src/app/modules/admin/apps/chat/chat.routes.ts new file mode 100644 index 00000000..c94bd148 --- /dev/null +++ b/frontend/src/app/modules/admin/apps/chat/chat.routes.ts @@ -0,0 +1,78 @@ +import { inject } from '@angular/core'; +import { + ActivatedRouteSnapshot, + Router, + RouterStateSnapshot, + Routes, +} from '@angular/router'; +import { ChatComponent } from 'app/modules/admin/apps/chat/chat.component'; +import { ChatService } from 'app/modules/admin/apps/chat/chat.service'; +import { ChatsComponent } from 'app/modules/admin/apps/chat/chats/chats.component'; +import { ConversationComponent } from 'app/modules/admin/apps/chat/conversation/conversation.component'; +import { EmptyConversationComponent } from 'app/modules/admin/apps/chat/empty-conversation/empty-conversation.component'; +import { catchError, throwError } from 'rxjs'; + +/** + * Conversation resolver + * + * @param route + * @param state + */ +const conversationResolver = ( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot +) => { + const chatService = inject(ChatService); + const router = inject(Router); + + return chatService.getChatById(route.paramMap.get('id')).pipe( + // Error here means the requested chat is not available + catchError((error) => { + // Log the error + console.error(error); + + // Get the parent url + const parentUrl = state.url.split('/').slice(0, -1).join('/'); + + // Navigate to there + router.navigateByUrl(parentUrl); + + // Throw an error + return throwError(error); + }) + ); +}; + +export default [ + { + path: '', + component: ChatComponent, + resolve: { + chats: () => inject(ChatService).getChats(), + }, + children: [ + { + path: '', + component: ChatsComponent, + children: [ + { + path: '', + pathMatch: 'full', + component: EmptyConversationComponent, + }, + { + path: 'new', + component: ConversationComponent, + }, + { + path: ':id', + component: ConversationComponent, + resolve: { + conversation: conversationResolver, + }, + }, + ], + }, + ], + }, +] as Routes; diff --git a/frontend/src/app/modules/admin/apps/chat/chat.service.ts b/frontend/src/app/modules/admin/apps/chat/chat.service.ts new file mode 100644 index 00000000..67086476 --- /dev/null +++ b/frontend/src/app/modules/admin/apps/chat/chat.service.ts @@ -0,0 +1,324 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Chat, LlmMessage } from 'app/modules/admin/apps/chat/chat.types'; +import { + BehaviorSubject, + Observable, + filter, + map, + of, + switchMap, + take, + tap, + throwError, +} from 'rxjs'; + +@Injectable({ providedIn: 'root' }) +export class ChatService { + private _chat: BehaviorSubject = new BehaviorSubject(null); + private _chats: BehaviorSubject = new BehaviorSubject(null); + + /** + * Constructor + */ + constructor(private _httpClient: HttpClient) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Getter for chat + */ + get chat$(): Observable { + return this._chat.asObservable(); + } + + /** + * Getter for chats + */ + get chats$(): Observable { + return this._chats.asObservable(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Get chats + */ + getChats(): Observable { + return this._httpClient.get('/api/chats').pipe( + tap((response: Chat[]) => { + response = (response as any).data.chats + this._chats.next(response); + }) + ); + } + + createChat(message: string, llmId: string): Observable { + return this._httpClient.post('/api/chat/new', { text: message, llmId }).pipe( + map((response: any) => { + const newChat: Chat = response.data; + const currentChats = this._chats.value || []; + this._chats.next([newChat, ...currentChats]); + return newChat; + }) + ); + } + + deleteChat(chatId: string): Observable { + return this._httpClient.delete(`/api/chat/${chatId}`).pipe( + tap(() => { + const currentChats = this._chats.value || []; + this._chats.next(currentChats.filter(chat => chat.id !== chatId)); + }) + ); + } + + /** + * Get chat + * + * @param id + */ + getChatById(id: string): Observable { + if(!id?.trim()) { + console.log(`nullish chat id "${id}"`) + const chat: Chat = {messages:[], id: null, title: ''} + this._chat.next(chat); + return this._chats + } + return this._httpClient + .get(`api/chat/${id}`) + .pipe( + map((chat: Chat) => { + // Update the chat + chat = (chat as any).data + + chat = { + id: chat.id, + lastMessage: (chat.messages[chat.messages.length - 1] as any).text, + title: chat.title, + messages: chat.messages.map(msg => { + const llmMsg = msg as LlmMessage + return { + ...msg, + value: llmMsg.text, + isMine: llmMsg.role === 'user' + } + }) + } + console.log(chat) + this._chat.next(chat); + + // Return the chat + return chat; + }), + switchMap((chat: Chat) => { + // chat = (chat as any).data + if (!chat) { + return throwError( + 'Could not found chat with id of ' + id + '!' + ); + } + + return of(chat); + }) + ); + } + + /** + * Update chat + * + * @param id + * @param chat + */ + updateChat(id: string, chat: Chat): Observable { + return this.chats$.pipe( + take(1), + switchMap((chats) => + this._httpClient + .patch('api/apps/chat/chat', { + id, + chat, + }) + .pipe( + map((updatedChat) => { + // Find the index of the updated chat + const index = chats.findIndex( + (item) => item.id === id + ); + + // Update the chat + chats[index] = updatedChat; + + // Update the chats + this._chats.next(chats); + + // Return the updated contact + return updatedChat; + }), + switchMap((updatedChat) => + this.chat$.pipe( + take(1), + filter((item) => item && item.id === id), + tap(() => { + // Update the chat if it's selected + this._chat.next(updatedChat); + + // Return the updated chat + return updatedChat; + }) + ) + ) + ) + ) + ); + } + + /** + * Update chat + * + * @param id + * @param chat + */ + updateChat2(id: string, chat: Chat): Observable { + return this.chats$.pipe( + take(1), + switchMap((chats) => + this._httpClient + .patch('api/apps/chat/chat', { + id, + chat, + }) + .pipe( + map((updatedChat) => { + // Find the index of the updated chat + const index = chats.findIndex( + (item) => item.id === id + ); + + // Update the chat + chats[index] = updatedChat; + + // Update the chats + this._chats.next(chats); + + // Update the chat if it's selected + this._chat.next(updatedChat); + + // Return the updated chat + return updatedChat; + }) + ) + ) + ); + } + + /** + * Reset the selected chat + */ + resetChat(): void { + this._chat.next({ id: '', messages: [], title: '' }); + } + + + /** + * Send a message + * + * @param chatId + * @param message + * @param llmId LLM identifier + */ + sendMessage(chatId: string, message: string, llmId: string): Observable { + return this.chats$.pipe( + take(1), + switchMap((chats) => + this._httpClient + .post(`api/chat/${chatId}/send`, { text: message, llmId }) + .pipe( + map((data: any) => { + const llmMessage = data.data; + + const newMessages = [ + { + value: message, + isMine: true, + }, + { + value: llmMessage, + isMine: false, + }, + ] + // // Find the index of the updated chat + const index = chats.findIndex( + (item) => item.id === chatId + ); + // + // // Update the chat + const chat = chats[index]; + chat.messages.push(...newMessages); + // // Update the chats + this._chats.next(chats); + // + // // Update the chat if it's selected + this._chat.next(chat); + // + // // Return the updated chat + return chat; + }) + ) + ) + ); + } + + /** + * Send an audio message + * + * @param chatId + * @param llmId + * @param audio + */ + sendAudioMessage(chatId: string, llmId: string, audio: Blob): Observable { + return this.chats$.pipe( + take(1), + switchMap((chats) => + this._httpClient + .post(`api/chat/${chatId}/send`, { audio: audio, llmId }) + .pipe( + map((data: any) => { + const llmMessage = data.data; + + // const newMessages = [ + // { + // value: message, + // isMine: true, + // }, + // { + // value: llmMessage, + // isMine: false, + // }, + // ] + // // Find the index of the updated chat + const index = chats.findIndex( + (item) => item.id === chatId + ); + // + // // Update the chat + const chat = chats[index]; + // chat.messages.push(...newMessages); + // // Update the chats + this._chats.next(chats); + // + // // Update the chat if it's selected + this._chat.next(chat); + // + // // Return the updated chat + return chat; + }) + ) + ) + ); + } +} diff --git a/frontend/src/app/modules/admin/apps/chat/chat.test.ts b/frontend/src/app/modules/admin/apps/chat/chat.test.ts new file mode 100644 index 00000000..ead71781 --- /dev/null +++ b/frontend/src/app/modules/admin/apps/chat/chat.test.ts @@ -0,0 +1,6 @@ +/* + +When the New Chat button is clicked: +- It should show an empty chat conversation, +- The message input field should gain focus. + */ \ No newline at end of file diff --git a/frontend/src/app/modules/admin/apps/chat/chat.types.ts b/frontend/src/app/modules/admin/apps/chat/chat.types.ts new file mode 100644 index 00000000..1c3ee645 --- /dev/null +++ b/frontend/src/app/modules/admin/apps/chat/chat.types.ts @@ -0,0 +1,63 @@ +export interface Profile { + id?: string; + name?: string; + email?: string; + avatar?: string; + about?: string; +} + +export interface Contact { + id?: string; + avatar?: string; + name?: string; + about?: string; + details?: { + emails?: { + email?: string; + label?: string; + }[]; + phoneNumbers?: { + country?: string; + phoneNumber?: string; + label?: string; + }[]; + title?: string; + company?: string; + birthday?: string; + address?: string; + }; + attachments?: { + media?: any[]; + docs?: any[]; + links?: any[]; + }; +} + +export interface LlmMessage { + role: 'system' | 'user' | 'assistant'; + text: string; + /** The LLM which generated the text (only when role=assistant) */ + llmId?: string; + /** Set the cache_control flag with Claude models */ + cache?: 'ephemeral'; + time?: number; +} + +export interface Chat { + id: string; + title: string; + contactId?: string; + contact?: Contact; + unreadCount?: number; + lastMessage?: string; + lastMessageAt?: string; + messages?: { + id?: string; + chatId?: string; + contactId?: string; + isMine?: boolean; + value?: string; + llmId?: string; + createdAt?: string; + }[]; +} diff --git a/frontend/src/app/modules/admin/apps/chat/chats/chats.component.html b/frontend/src/app/modules/admin/apps/chat/chats/chats.component.html new file mode 100644 index 00000000..f52582ab --- /dev/null +++ b/frontend/src/app/modules/admin/apps/chat/chats/chats.component.html @@ -0,0 +1,160 @@ +
+ + + + + + +
+ +
+ +
+ +
+ +
+ + + + +
+
+ + +
+ @if (filteredChats.length > 0) { + @for ( + chat of filteredChats; + track trackByFn($index, chat) + ) { + +
+
+ {{ chat.title }} +
+
+ {{ chat.lastMessage }} +
+
+
+
+ {{ chat.lastMessageAt }} +
+ @if (hoveredChatId === chat.id) { + + } +
+
+ } + } @else { +
+ +
+ No chats +
+
+ } +
+
+ + + + @if (chats !== null && chats !== undefined) { +
+ +
+ } +
+
+
diff --git a/frontend/src/app/modules/admin/apps/chat/chats/chats.component.ts b/frontend/src/app/modules/admin/apps/chat/chats/chats.component.ts new file mode 100644 index 00000000..017fa8c6 --- /dev/null +++ b/frontend/src/app/modules/admin/apps/chat/chats/chats.component.ts @@ -0,0 +1,125 @@ +import { NgClass } from '@angular/common'; +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + OnDestroy, + OnInit, + ViewEncapsulation, +} from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatSidenavModule } from '@angular/material/sidenav'; +import { RouterLink, RouterOutlet } from '@angular/router'; +import { ChatService } from 'app/modules/admin/apps/chat/chat.service'; +import { Chat } from 'app/modules/admin/apps/chat/chat.types'; +import { Subject, takeUntil } from 'rxjs'; + +@Component({ + selector: 'chat-chats', + templateUrl: './chats.component.html', + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [ + MatSidenavModule, + MatButtonModule, + MatIconModule, + MatMenuModule, + MatFormFieldModule, + MatInputModule, + NgClass, + RouterLink, + RouterOutlet, + ], +}) +export class ChatsComponent implements OnInit, OnDestroy { + chats: Chat[]; + filteredChats: Chat[]; + selectedChat: Chat; + hoveredChatId: string | null = null; + private _unsubscribeAll: Subject = new Subject(); + + /** + * Constructor + */ + constructor( + private _chatService: ChatService, + private _changeDetectorRef: ChangeDetectorRef, + ) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Chats + this._chatService.chats$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((chats: Chat[]) => { + this.chats = this.filteredChats = chats; + + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + + // Selected chat + this._chatService.chat$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((chat: Chat) => { + this.selectedChat = chat; + + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + + // Reset the chat + this._chatService.resetChat(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Filter the chats + * + * @param query + */ + filterChats(query: string): void { + // Reset the filter + if (!query) { + this.filteredChats = this.chats; + return; + } + + this.filteredChats = this.chats.filter((chat) => + chat.title.toLowerCase().includes(query.toLowerCase()) + ); + } + + /** + * Track by function for ngFor loops + * + * @param index + * @param item + */ + trackByFn(index: number, item: any): any { + return item.id || index; + } +} diff --git a/frontend/src/app/modules/admin/apps/chat/conversation/conversation.component.html b/frontend/src/app/modules/admin/apps/chat/conversation/conversation.component.html new file mode 100644 index 00000000..335dc367 --- /dev/null +++ b/frontend/src/app/modules/admin/apps/chat/conversation/conversation.component.html @@ -0,0 +1,261 @@ +
+ @if (chat) { + + + + + + + + + + +
+ + + + + + + + + +
+ + +
+
+ @for ( + message of chat.messages; + track trackByFn(i, message); + let i = $index; + let first = $first; + let last = $last + ) { + +
+ +
+ + @if ( + last || + chat.messages[i + 1].isMine !== + message.isMine + ) { +
+ +
+ } + +
+ +
+
+ + @if ( + first || + last || + chat.messages[i + 1].isMine !== + message.isMine || + chat.messages[i + 1].createdAt !== + message.createdAt + ) { +
+ {{ message.createdAt | date: 'HH:mm' }} +
+ } +
+ } +
+
+ + +
+ +
+ +
+ + + + + +
+ + + + @for (llm of $llms | async; track llm.id) { + + {{ llm.name }} + + } + + +
+ + + + + +
+ +
+
+
+
+ } @else { +
+ +
+ Start a new chat +
+
+ } + + + + + + + + + + + + +
diff --git a/frontend/src/app/modules/admin/apps/chat/conversation/conversation.component.scss b/frontend/src/app/modules/admin/apps/chat/conversation/conversation.component.scss new file mode 100644 index 00000000..7474f6bd --- /dev/null +++ b/frontend/src/app/modules/admin/apps/chat/conversation/conversation.component.scss @@ -0,0 +1,44 @@ +.selected-button { + background-color: rgba(var(--fuse-primary-rgb), 0.1); +} + +.text-primary { + color: var(--fuse-primary) !important; +} + +.recording-button { + background-color: rgba(var(--fuse-primary-rgb), 0.1); + + mat-icon { + color: var(--fuse-primary); + } +} + +.chat-row { + position: relative; + display: flex; + align-items: center; + padding: 8px; + + &:hover { + background-color: #f5f5f5; + } + + .chat-row-content { + flex: 1; + } + + .delete-button { + position: absolute; + right: 8px; + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + transition: opacity 0.2s; + } + + &:hover .delete-button { + opacity: 1; + } +} diff --git a/frontend/src/app/modules/admin/apps/chat/conversation/conversation.component.ts b/frontend/src/app/modules/admin/apps/chat/conversation/conversation.component.ts new file mode 100644 index 00000000..d5e619b8 --- /dev/null +++ b/frontend/src/app/modules/admin/apps/chat/conversation/conversation.component.ts @@ -0,0 +1,373 @@ +import { TextFieldModule } from '@angular/cdk/text-field'; +import {AsyncPipe, DatePipe, NgClass, NgTemplateOutlet} from '@angular/common'; +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + ElementRef, + HostListener, + NgZone, + OnDestroy, + OnInit, + ViewChild, + ViewEncapsulation, +} from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatSidenavModule } from '@angular/material/sidenav'; +import {Router, RouterLink, RouterModule, ActivatedRoute} from '@angular/router'; +import { FuseMediaWatcherService } from '@fuse/services/media-watcher'; +import { ChatService } from 'app/modules/admin/apps/chat/chat.service'; +import { Chat } from 'app/modules/admin/apps/chat/chat.types'; +import { ChatInfoComponent } from 'app/modules/admin/apps/chat/chat-info/chat-info.component'; +import { LLM, LlmService } from "app/modules/agents/services/llm.service"; +import {BehaviorSubject, Observable, Subject, takeUntil} from 'rxjs'; +import { + CLIPBOARD_OPTIONS, + ClipboardButtonComponent, + MarkdownModule, + MarkdownService, + provideMarkdown +} from "ngx-markdown"; +import {MatOption} from "@angular/material/core"; +import {MatSelect} from "@angular/material/select"; +import {ReactiveFormsModule} from "@angular/forms"; +import {MatCheckbox} from "@angular/material/checkbox"; +import {MatTooltipModule} from "@angular/material/tooltip"; + + +@Component({ + selector: 'chat-conversation', + templateUrl: './conversation.component.html', + styleUrls: ['./conversation.component.scss'], + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [ + MatSidenavModule, + ChatInfoComponent, + MatButtonModule, + RouterLink, + MatIconModule, + MatMenuModule, + MatButtonModule, + MatMenuModule, + MatTooltipModule, + NgClass, + NgTemplateOutlet, + MatFormFieldModule, + MatInputModule, + TextFieldModule, + DatePipe, + MarkdownModule, + AsyncPipe, + RouterModule, + MatOption, + MatSelect, + ReactiveFormsModule, + ], + providers: [ + provideMarkdown({ + clipboardOptions: { + provide: CLIPBOARD_OPTIONS, + useValue: { + buttonComponent: ClipboardButtonComponent, + }, + }, + }) + ] +}) +export class ConversationComponent implements OnInit, OnDestroy { + + @ViewChild('messageInput') messageInput: ElementRef; + chat: Chat; + drawerMode: 'over' | 'side' = 'side'; + drawerOpened: boolean = false; + private _unsubscribeAll: Subject = new Subject(); + $llms: BehaviorSubject = new BehaviorSubject(null); + llmId: string; + sendIcon: string = 'heroicons_outline:paper-airplane' + sendOnEnter: boolean = true; + private mediaRecorder: MediaRecorder; + private audioChunks: Blob[] = []; + recording: boolean = false; + + /** + * Constructor + */ + constructor( + private _changeDetectorRef: ChangeDetectorRef, + private _chatService: ChatService, + private _fuseMediaWatcherService: FuseMediaWatcherService, + private _ngZone: NgZone, + private _elementRef: ElementRef, + private _markdown: MarkdownService, + private llmService: LlmService, + private router: Router, + private route: ActivatedRoute + ) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Decorated methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Resize on 'input' and 'ngModelChange' events + * + * @private + */ + @HostListener('input') + @HostListener('ngModelChange') + private _resizeMessageInput(): void { + // This doesn't need to trigger Angular's change detection by itself + this._ngZone.runOutsideAngular(() => { + setTimeout(() => { + // Set the height to 'auto' so we can correctly read the scrollHeight + this.messageInput.nativeElement.style.height = 'auto'; + + // Detect the changes so the height is applied + this._changeDetectorRef.detectChanges(); + + // Get the scrollHeight and subtract the vertical padding + this.messageInput.nativeElement.style.height = `${this.messageInput.nativeElement.scrollHeight}px`; + + // Detect the changes one more time to apply the final height + this._changeDetectorRef.detectChanges(); + }); + }); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Subscribe to route parameters + this.route.params + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(params => { + const chatId = params['id']; + + if (chatId === 'new' || !chatId) { + // If 'new' or no ID, reset the chat + this.resetChat(); + } else { + // Load the chat by ID + this._chatService.getChatById(chatId).subscribe(); + } + }); + + // Chat observable + this._chatService.chat$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((chat: Chat) => { + this.chat = chat || { id: '', messages: [], title: '' }; + if(chat.messages.length > 0) { + // Set the LLM selector as the LLM used to send the last message + const lastMessageLlmId = chat.messages.at(-1).llmId + if (lastMessageLlmId) { // TODO check the llmId is in the $llm list + this.llmId = lastMessageLlmId; + console.log(`last message llm ${this.llmId}`) + } else { + // TODO default to user profile default chat LLM + } + } + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + + // Media watcher (unchanged) + this._fuseMediaWatcherService.onMediaChange$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(({ matchingAliases }) => { + this.drawerMode = matchingAliases.includes('lg') ? 'side' : 'over'; + this._changeDetectorRef.markForCheck(); + }); + + // Load LLMs (unchanged) + this.llmService.getLlms().subscribe(llms => { + this.$llms.next(llms); + this.llmId = llms[0]?.id; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Open the contact info + */ + openChatInfo(): void { + // Open the drawer + this.drawerOpened = true; + + // Mark for check + this._changeDetectorRef.markForCheck(); + } + + /** + * Reset the chat + */ + resetChat(): void { + const newChat: Chat = { id: '', messages: [], title: '' }; + this.chat = newChat; + this._chatService.resetChat(); + + // TODO set LLM field to the user profile default chat LLM + + // Close the contact info in case it's opened + this.drawerOpened = false; + + // Clear the input field + if (this.messageInput) { + this.messageInput.nativeElement.value = ''; + } + + // Mark for check + this._changeDetectorRef.markForCheck(); + } + + /** + * Delete the current chat + */ + deleteChat(): void { + if (this.chat && this.chat.id) { + this._chatService.deleteChat(this.chat.id).subscribe(() => { + this.resetChat(); + this.router.navigate(['/apps/chat']).catch(console.error); + }); + } + } + + /** + * Track by function for ngFor loops + * + * @param index + * @param item + */ + trackByFn(index: number, item: any): any { + return item.id || index; + } + + sendMessage(): void { + const message = this.messageInput.nativeElement.value.trim(); + if (message === '') { + return; + } + + // If this is a new chat, then redirect to the created chat + if (!this.chat.id) { + this.chat.messages.push({ + value: message, + isMine: true, + }) + this.messageInput.nativeElement.value = ''; + this._changeDetectorRef.markForCheck(); + // TODO handle error, set the message back to the messageInput and remove from chat.messages + this._chatService.createChat(message, this.llmId).subscribe(async (chat: Chat) => { + this.router.navigate([`/apps/chat/${chat.id}`]).catch(console.error); + }); + + return; + } + + this.sendIcon = 'heroicons_outline:stop-circle' + this._chatService.sendMessage(this.chat.id, message, this.llmId).subscribe(() => { + this.sendIcon = 'heroicons_outline:paper-airplane' + // Clear the input + this.messageInput.nativeElement.value = ''; + this._resizeMessageInput(); + this._scrollToBottom(); + + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + } + + private _scrollToBottom(): void { + setTimeout(() => { + const chatElement = this._elementRef.nativeElement.querySelector('.conversation-container'); + chatElement.scrollTop = chatElement.scrollHeight; + }); + } + + @HostListener('keydown', ['$event']) + handleKeyboardEvent(event: KeyboardEvent): void { + if (this.sendOnEnter && event.key === 'Enter' && !event.shiftKey) { + event.preventDefault(); + this.sendMessage(); + } + } + + toggleSendOnEnter(): void { + this.sendOnEnter = !this.sendOnEnter; + this._changeDetectorRef.markForCheck(); + } + + startRecording(): void { + if (this.recording) return; + + navigator.mediaDevices.getUserMedia({ audio: true }) + .then(stream => { + this.recording = true; + this.mediaRecorder = new MediaRecorder(stream); + this.mediaRecorder.start(); + this.audioChunks = []; + + this.mediaRecorder.addEventListener('dataavailable', event => { + this.audioChunks.push(event.data); + }); + + this.mediaRecorder.addEventListener('stop', () => { + const audioBlob = new Blob(this.audioChunks, { type: 'audio/webm' }); + this.audioChunks = []; + + // Send the audio message + this.sendAudioMessage(audioBlob); + }); + }) + .catch(error => { + console.error('Error accessing microphone', error); + // TODO Handle permission errors or show a message to the user + }); + } + + stopRecording(): void { + if (!this.recording) return; + + this.recording = false; + this.mediaRecorder.stop(); + + // Stop all tracks to release the microphone + this.mediaRecorder.stream.getTracks().forEach(track => track.stop()); + } + + sendAudioMessage(audioBlob: Blob): void { + this._chatService.sendAudioMessage(this.chat.id, this.llmId, audioBlob).subscribe( + () => { + // Handle successful send, update the UI if necessary + this._changeDetectorRef.markForCheck(); + }, + error => { + // Handle error + console.error('Error sending audio message', error); + } + ); + } +} diff --git a/frontend/src/app/modules/admin/apps/chat/empty-conversation/empty-conversation.component.html b/frontend/src/app/modules/admin/apps/chat/empty-conversation/empty-conversation.component.html new file mode 100644 index 00000000..2e1591d4 --- /dev/null +++ b/frontend/src/app/modules/admin/apps/chat/empty-conversation/empty-conversation.component.html @@ -0,0 +1,16 @@ +
+ +
+ +
+ Select a conversation or start a new chat +
+
+
diff --git a/frontend/src/app/modules/admin/apps/chat/empty-conversation/empty-conversation.component.ts b/frontend/src/app/modules/admin/apps/chat/empty-conversation/empty-conversation.component.ts new file mode 100644 index 00000000..1e27c13a --- /dev/null +++ b/frontend/src/app/modules/admin/apps/chat/empty-conversation/empty-conversation.component.ts @@ -0,0 +1,21 @@ +import { + ChangeDetectionStrategy, + Component, + ViewEncapsulation, +} from '@angular/core'; +import { MatIconModule } from '@angular/material/icon'; + +@Component({ + selector: 'chat-empty-conversation', + templateUrl: './empty-conversation.component.html', + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [MatIconModule], +}) +export class EmptyConversationComponent { + /** + * Constructor + */ + constructor() {} +} diff --git a/frontend/src/app/modules/admin/home/home.component.html b/frontend/src/app/modules/admin/home/home.component.html new file mode 100644 index 00000000..6ccbf3b2 --- /dev/null +++ b/frontend/src/app/modules/admin/home/home.component.html @@ -0,0 +1,9 @@ +
+ +
+ +
+
+
diff --git a/frontend/src/app/modules/admin/home/home.component.ts b/frontend/src/app/modules/admin/home/home.component.ts new file mode 100644 index 00000000..0321aeef --- /dev/null +++ b/frontend/src/app/modules/admin/home/home.component.ts @@ -0,0 +1,17 @@ +import { Component, ViewEncapsulation } from '@angular/core'; + +@Component({ + selector : 'example', + standalone : true, + templateUrl : './home.component.html', + encapsulation: ViewEncapsulation.None, +}) +export class HomeComponent +{ + /** + * Constructor + */ + constructor() + { + } +} diff --git a/frontend/src/app/modules/admin/home/home.routes.ts b/frontend/src/app/modules/admin/home/home.routes.ts new file mode 100644 index 00000000..f9c94d1a --- /dev/null +++ b/frontend/src/app/modules/admin/home/home.routes.ts @@ -0,0 +1,9 @@ +import { Routes } from '@angular/router'; +import { HomeComponent } from 'app/modules/admin/home/home.component'; + +export default [ + { + path : '', + component: HomeComponent, + }, +] as Routes; diff --git a/frontend/src/app/modules/agents/agent-list/agent-list.component.html b/frontend/src/app/modules/agents/agent-list/agent-list.component.html new file mode 100644 index 00000000..2c222d20 --- /dev/null +++ b/frontend/src/app/modules/agents/agent-list/agent-list.component.html @@ -0,0 +1,153 @@ +
+ +
+ + @if (isLoading) { +
+ +
+ } + +
Agents
+ +
+ + + + + + + +
+
+ + +
+
+ @if (agents$ | async; as products) { + @if (products.length > 0) { +
+ +
+ +
+ + +
Name
+ + +
State
+ +
Type
+ + +
User Prompt
+ + +
Error/Output
+ + +
Cost
+
+ + @if (agents$ | async; as agents) { + @for (agent of agents; track trackByFn($index, agent)) { +
+ +
+ + +
+ + + + + +
{{ agent.state }}
+ + +
{{ agent.type }}
+ + +
{{ agent.userPrompt | slice: 0 : 150 }}
+ + +
+ {{ (agent.state === 'error' ? agent.error : agent.output) | slice: 0 : 150 }} +
+ + +
${{ agent.cost | number: '1.2-2' }}
+
+ } + } +
+ + } @else { +
+
There are no agents!
+ + + +
+ } + } +
+
+
diff --git a/frontend/src/app/modules/agents/agent-list/agent-list.component.ts b/frontend/src/app/modules/agents/agent-list/agent-list.component.ts new file mode 100644 index 00000000..efbb9cbb --- /dev/null +++ b/frontend/src/app/modules/agents/agent-list/agent-list.component.ts @@ -0,0 +1,372 @@ +import { + AsyncPipe, + CurrencyPipe, + NgClass, + NgTemplateOutlet, SlicePipe, DecimalPipe +} from '@angular/common'; +import { + AfterViewInit, + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + OnDestroy, + OnInit, + ViewChild, + ViewEncapsulation, +} from '@angular/core'; +import { + FormsModule, + ReactiveFormsModule, + UntypedFormBuilder, + UntypedFormControl, + UntypedFormGroup, + Validators, +} from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { + MatCheckboxChange, + MatCheckboxModule, +} from '@angular/material/checkbox'; +import { MatOptionModule, MatRippleModule } from '@angular/material/core'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator'; +import { MatProgressBarModule } from '@angular/material/progress-bar'; +import { MatSelectModule } from '@angular/material/select'; +import { MatSlideToggleModule } from '@angular/material/slide-toggle'; +import { MatSort, MatSortModule } from '@angular/material/sort'; +import { fuseAnimations } from '@fuse/animations'; +import { FuseConfirmationService } from '@fuse/services/confirmation'; +import { AgentService } from 'app/modules/agents/services/agent.service'; +import { + AgentContext, + AgentType, + AgentPagination, + AgentTag, +} from 'app/modules/agents/agent.types'; +import { + Observable, + Subject, + debounceTime, + map, + merge, + switchMap, + takeUntil, +} from 'rxjs'; +import {SelectionModel} from "@angular/cdk/collections"; +import {RouterModule} from "@angular/router"; + +@Component({ + selector: 'inventory-list', + templateUrl: './agent-list.component.html', + styles: [ + /* language=SCSS */ + ` + .inventory-grid { + grid-template-columns: 48px auto 40px; + + @screen sm { + grid-template-columns: 48px auto 112px 72px; + } + + @screen md { + grid-template-columns: 48px 112px auto 112px 72px; + } + + @screen lg { + grid-template-columns: 48px 112px auto 112px 96px 96px 72px; + } + } + `, + ], + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + animations: fuseAnimations, + standalone: true, + imports: [ + MatProgressBarModule, + MatFormFieldModule, + MatIconModule, + MatInputModule, + FormsModule, + ReactiveFormsModule, + MatButtonModule, + MatSortModule, + MatPaginatorModule, + NgClass, + MatSlideToggleModule, + MatSelectModule, + MatOptionModule, + MatCheckboxModule, + MatRippleModule, + AsyncPipe, + SlicePipe, + DecimalPipe, + RouterModule, + ], +}) +export class AgentListComponent + implements OnInit, AfterViewInit, OnDestroy +{ + @ViewChild(MatPaginator) private _paginator: MatPaginator; + @ViewChild(MatSort) private _sort: MatSort; + + agents$: Observable; + + agentTypes: AgentType[]; + filteredTags: AgentTag[]; + flashMessage: 'success' | 'error' | null = null; + isLoading: boolean = false; + pagination: AgentPagination; + searchInputControl: UntypedFormControl = new UntypedFormControl(); + tags: AgentTag[]; + tagsEditMode: boolean = false; + + selection = new SelectionModel(true, []); + + private _unsubscribeAll: Subject = new Subject(); + + /** + * Constructor + */ + constructor( + private _changeDetectorRef: ChangeDetectorRef, + private _fuseConfirmationService: FuseConfirmationService, + private _formBuilder: UntypedFormBuilder, + private _inventoryService: AgentService + ) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Get the pagination + this._inventoryService.pagination$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((pagination: AgentPagination) => { + // Update the pagination + this.pagination = pagination; + + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + + // Get the products + this.agents$ = this._inventoryService.agents$; + + this._inventoryService.getAgents(); + + this._inventoryService.agents$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((agents: AgentContext[]) => { + // Update the vendors + // this.a = vendors; + + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + + // Subscribe to search input field value changes + this.searchInputControl.valueChanges + .pipe( + takeUntil(this._unsubscribeAll), + debounceTime(300), + switchMap((query) => { + this.isLoading = true; + return this._inventoryService.getAgents(); + }), + map(() => { + this.isLoading = false; + }) + ) + .subscribe(); + } + + /** + * After view init + */ + ngAfterViewInit(): void { + if (this._sort && this._paginator) { + // Set the initial sort + this._sort.sort({ + id: 'name', + start: 'asc', + disableClear: true, + }); + + // Mark for check + this._changeDetectorRef.markForCheck(); + + // If the user changes the sort order... + this._sort.sortChange + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + // Reset back to the first page + this._paginator.pageIndex = 0; + }); + + // Get products if sort or page changes + merge(this._sort.sortChange, this._paginator.page) + .pipe( + switchMap(() => { + this.isLoading = true; + return this._inventoryService.getAgents( ); + }), + map(() => { + this.isLoading = false; + }) + ) + .subscribe(); + } + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + + isAllSelected(): boolean { + // const numSelected = this.selection.selected.length; + // const numRows = this.agents.length; + // return numSelected === numRows && numRows > 0; + return false; + } + + masterToggle(): void { + if (this.isAllSelected()) { + this.selection.clear(); + } else { + // this.agents.forEach(row => this.selection.select(row)); + } + } + + deleteSelectedAgents(): void { + const selectedAgentIds = this.selection.selected.map(agent => agent.agentId); + if (selectedAgentIds.length === 0) { + // this._snackBar.open('No agents selected for deletion', 'Close', { duration: 3000 }); + return; + } + + this._inventoryService.deleteAgents(selectedAgentIds).subscribe({ + next: () => { + // this._snackBar.open('Agents deleted successfully', 'Close', { duration: 3000 }); + this.refreshAgents(); + this.selection.clear(); + }, + error: (error) => { + console.error('Error deleting agents:', error); + // this._snackBar.open('Error deleting agents', 'Close', { duration: 3000 }); + }, + }); + } + + refreshAgents(): void { + this._inventoryService.getAgents().subscribe({ + next: () => { + // this._snackBar.open('Agents refreshed', 'Close', { duration: 1000 }); + }, + error: (error) => { + console.error('Error refreshing agents:', error); + // this._snackBar.open('Error refreshing agents', 'Close', { duration: 3000 }); + }, + }); + } + + /** + * Create product + */ + createProduct(): void { + console.log('TODO navigate') + } + // createProduct(): void { + // // Create the product + // this._inventoryService.createProduct().subscribe((newProduct) => { + // // Go to new product + // this.selectedProduct = newProduct; + // + // // Fill the form + // this.selectedProductForm.patchValue(newProduct); + // + // // Mark for check + // this._changeDetectorRef.markForCheck(); + // }); + // } + // + + /** + * Delete the selected product using the form data + */ + deleteSelectedProduct(): void { + // Open the confirmation dialog + const confirmation = this._fuseConfirmationService.open({ + title: 'Delete product', + message: + 'Are you sure you want to remove this product? This action cannot be undone!', + actions: { + confirm: { + label: 'Delete', + }, + }, + }); + + // Subscribe to the confirmation dialog closed action + confirmation.afterClosed().subscribe((result) => { + // If the confirm button pressed... + if (result === 'confirmed') { + // Get the product object + // const product = this.selectedProductForm.getRawValue(); + // + // // Delete the product on the server + // this._inventoryService + // .deleteProduct(product.id) + // .subscribe(() => { + // // Close the details + // this.closeDetails(); + // }); + } + }); + } + + /** + * Show flash message + */ + showFlashMessage(type: 'success' | 'error'): void { + // Show the message + this.flashMessage = type; + + // Mark for check + this._changeDetectorRef.markForCheck(); + + // Hide it after 3 seconds + setTimeout(() => { + this.flashMessage = null; + + // Mark for check + this._changeDetectorRef.markForCheck(); + }, 3000); + } + + /** + * Track by function for ngFor loops + * + * @param index + * @param item + */ + trackByFn(index: number, item: any): any { + return item.id || index; + } +} diff --git a/frontend/src/app/modules/agents/agent.routes.ts b/frontend/src/app/modules/agents/agent.routes.ts new file mode 100644 index 00000000..ae1b7c50 --- /dev/null +++ b/frontend/src/app/modules/agents/agent.routes.ts @@ -0,0 +1,29 @@ +import { Routes } from '@angular/router'; +import { inject } from '@angular/core'; +import { AgentService } from 'app/modules/agents/services/agent.service'; +import { AgentListComponent } from 'app/modules/agents/agent-list/agent-list.component'; +import { NewAgentComponent } from "./new-agent/new-agent.component"; +import { AgentComponent } from "./agent/agent.component"; + +export default [ + { + path: '', + pathMatch: 'full', + redirectTo: 'list', + }, + { + path: 'new', + component: NewAgentComponent, + }, + { + path: 'list', + component: AgentListComponent, + resolve: { + agents: () => inject(AgentService).getAgents(), + }, + }, + { + path: ':id', + component: AgentComponent, + }, +] as Routes; diff --git a/frontend/src/app/modules/agents/agent.types.ts b/frontend/src/app/modules/agents/agent.types.ts new file mode 100644 index 00000000..109fe0e7 --- /dev/null +++ b/frontend/src/app/modules/agents/agent.types.ts @@ -0,0 +1,149 @@ +export interface AgentPagination { + length: number; + size: number; + page: number; + lastPage: number; + startIndex: number; + endIndex: number; +} + +export interface AgentType { + id: string; + parentId: string; + name: string; + slug: string; +} + +export interface AgentTag { + id?: string; + title?: string; +} + + +export type TaskLevel = 'easy' | 'medium' | 'hard' | 'xhard'; + +interface LLM { + /** + * The LLM model identifier + */ + getModel(): string; + + getService(): string; +} + +/** + * The LLMs for each Task Level + */ +export type AgentLLMs = Record; + +export interface FunctionCall { + function_name: string; + parameters: { [key: string]: any }; +} + +export interface FunctionCallResult extends FunctionCall { + stdout?: string; + stderr?: string; + + stdoutExpanded: boolean; + stdoutSummary?: string; + stderrExpanded: boolean; + stderrSummary?: string; +} + +/** + * agent - waiting for the agent LLM call(s) to generate control loop update + * functions - waiting for the planned function call(s) to complete + * error - the agent control loop has errored + * hil - deprecated for humanInLoop_agent and humanInLoop_tool + * hitl_threshold - If the agent has reached budget or iteration thresholds. At this point the agent is not executing any LLM/function calls. + * hitl_tool - When a function has request HITL in the function calling part of the control loop + * hitl_feedback - the agent has requested human feedback for a decision. At this point the agent is not executing any LLM/function calls. + * hil - deprecated version of hitl_feedback + * feedback - deprecated version of hitl_feedback + * child_agents - waiting for child agents to complete + * completed - the agent has called the completed function. + * shutdown - if the agent has been instructed by the system to pause (e.g. for server shutdown) + * timeout - for chat agents when there hasn't been a user input for a configured amount of time + */ +export type AgentRunningState = + | 'agent' + | 'functions' + | 'error' + | 'hil' + | 'hitl_threshold' + | 'hitl_tool' + | 'feedback' + | 'hitl_feedback' + | 'completed' + | 'shutdown' + | 'child_agents' + | 'timeout'; + +export interface AgentContext { + /** Agent instance id - allocated when the agent is first starts */ + agentId: string; + /** Id of the running execution. This changes after the control loop restarts after an exit due to pausing, human in loop etc */ + executionId: string; + traceId: string; + name: string; + parentAgentId?: string; + isRetry: boolean; + /** Empty string in single-user mode */ + userId: string; + userEmail?: string; + type: AgentType; + state: AgentRunningState; + inputPrompt: string; + userPrompt: string; + systemPrompt: string; + functionCallHistory: FunctionCallResult[]; + + // These three fields are mutable for when saving state as the agent does work + error?: string; + planningResponse?: string; + invoking: FunctionCall[]; + /** Total cost of running this agent */ + cost: number; + /** Budget allocated until human intervention is required. This may be increased when the agent is running */ + budget: number; + /** Budget remaining until human intervention is required */ + budgetRemaining: number; + + llms: { easy: string; medium: string; hard: string; xhard: string }; + + /** Working filesystem */ + fileSystem: { workingDirectory: string }; + /** The functions available to the agent */ + functions: string[]; + /** Memory persisted over the agent's control loop iterations */ + memory: Map; + + // UI generated + output: string; +} + + +export interface LlmCall { + id: string; + description?: string; + systemPrompt?: string; + userPrompt: string; + agentId?: string; + userId?: string; + callStack?: string; + llmId: string; + requestTime: number; + responseText?: string; + timeToFirstToken?: number; + totalTime?: number; + cost?: number; + inputTokens: number; + outputTokens: number; + + systemPromptExpanded: boolean; + functionCallHistoryExpanded: boolean; + memoryContentsExpanded: boolean; + userPromptExpanded: boolean; + responseTextExpanded: boolean; +} diff --git a/frontend/src/app/modules/agents/agent/agent-details/agent-details.component.html b/frontend/src/app/modules/agents/agent/agent-details/agent-details.component.html new file mode 100644 index 00000000..8dc80bf6 --- /dev/null +++ b/frontend/src/app/modules/agents/agent/agent-details/agent-details.component.html @@ -0,0 +1,215 @@ +@if(agentDetails) { + + + Feedback Requested + + + + + Question: + {{ + agentDetails.functionCallHistory[agentDetails.functionCallHistory.length - 1].parameters[ + 'request' + ].trim() | slice : 0 : 140 + }}... + + +
{{ agentDetails.functionCallHistory[agentDetails.functionCallHistory.length - 1].parameters['request'].trim() }} +
+
+ + + +
+ + + + + +
+ + +
+ Agent Error + + + + + Error: + {{ agentDetails.error | slice : 0 : 150 }}... + + +
{{ agentDetails.error }}
+
+ + + +
+ + + + +
+
+ + +
+ Human In Loop check + + + + + + + + + +
+
+ + +
+ refresh + + storage + +
+ +
+
+ Name + {{ agentDetails.name }} +
+ +
+ Type + {{ agentDetails.type }} +
+ +
+ State + {{ displayState(agentDetails.state) }} + Resume + agent +
+
+ + +
+
+ Parent Agent ID + {{ agentDetails.parentAgentId }} +
+ +
+ User ID + {{ agentDetails.userId }} +
+
+ + + User prompt + + + + {{ + agentDetails.userPrompt | slice : 0 : 150 + }} + + +
{{ agentDetails.userPrompt }}
+
+ + @if (agentDetails.state === 'completed') { + Output + + + + {{ + agentDetails.output | slice : 0 : 150 + }} + + +
{{ agentDetails.output }}
+
+ } + + Functions + +
+ {{ agentDetails.functions.sort().join(', ') }} + +
+ + LLMS + +
+
+ Easy: + {{ getLlmName(agentDetails.llms.easy) }} +
+
+ Med: + {{ getLlmName(agentDetails.llms.medium) }} +
+
+ Hard: + {{ getLlmName(agentDetails.llms.hard) }} +
+
+ + +
+ Cost + ${{ agentDetails.cost | number : '1.2-2' }} +
+ +
+ Working Directory + {{ agentDetails.fileSystem.workingDirectory }} +
+ +
+} @else { + +} + diff --git a/frontend/src/app/agent/agent.component.scss b/frontend/src/app/modules/agents/agent/agent-details/agent-details.component.scss similarity index 100% rename from frontend/src/app/agent/agent.component.scss rename to frontend/src/app/modules/agents/agent/agent-details/agent-details.component.scss diff --git a/frontend/src/app/modules/agents/agent/agent-details/agent-details.component.ts b/frontend/src/app/modules/agents/agent/agent-details/agent-details.component.ts new file mode 100644 index 00000000..fbc92f83 --- /dev/null +++ b/frontend/src/app/modules/agents/agent/agent-details/agent-details.component.ts @@ -0,0 +1,339 @@ +import {ChangeDetectorRef, Component, Input, OnInit} from '@angular/core'; +import { AgentContext, AgentRunningState } from '../../agent.types'; +import { CommonModule } from '@angular/common'; +import { MatCardModule } from '@angular/material/card'; +import { MatListModule } from '@angular/material/list'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatExpansionModule } from '@angular/material/expansion'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { HttpClient } from '@angular/common/http'; +import { MatSnackBar } from '@angular/material/snack-bar'; +import { environment } from 'environments/environment'; +import { catchError, finalize } from 'rxjs/operators'; +import {map, of, throwError} from 'rxjs'; +import { MatDialog } from '@angular/material/dialog'; +import { FunctionEditModalComponent } from '../function-edit-modal/function-edit-modal.component'; +import { ResumeAgentModalComponent } from '../resume-agent-modal/resume-agent-modal.component'; +import {MatSelectModule} from "@angular/material/select"; +import {MatCheckboxModule} from "@angular/material/checkbox"; +import {MatRadioModule} from "@angular/material/radio"; +import {FunctionsService} from "../../services/function.service"; + +@Component({ + selector: 'agent-details', + templateUrl: './agent-details.component.html', + styleUrl: 'agent-details.component.scss', + standalone: true, + imports: [ + CommonModule, + MatCardModule, + MatListModule, + MatButtonModule, + MatIconModule, + MatExpansionModule, + MatFormFieldModule, + MatInputModule, + ReactiveFormsModule, + MatSelectModule, + MatCheckboxModule, + MatRadioModule, + ], +}) +export class AgentDetailsComponent implements OnInit { + @Input() agentDetails!: AgentContext; + + feedbackForm!: FormGroup; + hilForm!: FormGroup; + errorForm!: FormGroup; + isSubmitting: boolean = false; + isResumingError: boolean = false; + userPromptExpanded: boolean = false; + outputExpanded: boolean = false; + allAvailableFunctions: string[] = []; // Initialize with an empty array or fetch from a service + llmNameMap: Map = new Map(); + + constructor( + private formBuilder: FormBuilder, + private http: HttpClient, + private snackBar: MatSnackBar, + private dialog: MatDialog, + private functionsService: FunctionsService, + private changeDetectorRef: ChangeDetectorRef, + ) {} + + ngOnInit(): void { + this.initializeFeedbackForm(); + this.initializeHilForm(); + this.initializeErrorForm(); + // Load available functions here, possibly from a service + this.functionsService.getFunctions().subscribe(value => + this.allAvailableFunctions = value) + this.http + .get<{ data: Array<{ id: string; name: string }> }>(`${environment.serverUrl}llms/list`) + .pipe( + map((response) => { + console.log(response); + return response.data as Array<{ id: string; name: string }>; + }) + ) + .subscribe((llms) => { + this.llmNameMap = new Map(llms.map((llm) => [llm.id, llm.name])); + }); + } + + private initializeFeedbackForm(): void { + this.feedbackForm = this.formBuilder.group({ + feedback: ['', Validators.required], + }); + } + + private initializeHilForm(): void { + this.hilForm = this.formBuilder.group({ + feedback: [''], + }); + } + + private initializeErrorForm(): void { + this.errorForm = this.formBuilder.group({ + errorDetails: ['', Validators.required], + }); + } + + onSubmitFeedback(): void { + if (!this.feedbackForm.valid) return; + const feedback = this.feedbackForm.get('feedback')?.value; + this.isSubmitting = true; + this.http + .post(`${environment.serverUrl}/agent/v1/feedback`, { + agentId: this.agentDetails.agentId, + executionId: this.agentDetails.executionId, + feedback: feedback, + }) + .pipe( + catchError((error) => { + console.error('Error submitting feedback:', error); + this.snackBar.open('Error submitting feedback', 'Close', { duration: 3000 }); + return of(null); + }), + finalize(() => { + this.isSubmitting = false; + }) + ) + .subscribe((response) => { + if (response) { + this.snackBar.open('Feedback submitted successfully', 'Close', { duration: 3000 }); + // Optionally reload or update agent details + } + }); + } + + onResumeHil(): void { + if (!this.hilForm.valid) return; + this.isSubmitting = true; + const feedback = this.hilForm.get('feedback')?.value; + this.http + .post(`${environment.serverUrl}/agent/v1/resume-hil`, { + agentId: this.agentDetails.agentId, + executionId: this.agentDetails.executionId, + feedback, + }) + .pipe( + catchError((error) => { + console.error('Error resuming agent:', error); + this.snackBar.open('Error resuming agent', 'Close', { duration: 3000 }); + return of(null); + }), + finalize(() => { + this.isSubmitting = false; + }) + ) + .subscribe((response) => { + if (response) { + this.snackBar.open('Agent resumed successfully', 'Close', { duration: 3000 }); + this.hilForm.reset(); + // Optionally reload or update agent details + } + }); + } + + onResumeError(): void { + if (!this.errorForm.valid) return; + this.isResumingError = true; + const errorDetails = this.errorForm.get('errorDetails')?.value; + this.http + .post(`${environment.serverUrl}/agent/v1/resume-error`, { + agentId: this.agentDetails.agentId, + executionId: this.agentDetails.executionId, + feedback: errorDetails, + }) + .pipe( + catchError((error) => { + console.error('Error resuming agent:', error); + this.snackBar.open('Error resuming agent', 'Close', { duration: 3000 }); + return of(null); + }), + finalize(() => { + this.isResumingError = false; + }) + ) + .subscribe((response) => { + if (response) { + this.snackBar.open('Agent resumed successfully', 'Close', { duration: 3000 }); + this.errorForm.reset(); + // Optionally reload or update agent details + } + }); + } + + cancelAgent(): void { + this.http + .post(`${environment.serverUrl}/agent/v1/cancel`, { + agentId: this.agentDetails.agentId, + executionId: this.agentDetails.executionId, + reason: 'None provided', + }) + .pipe( + catchError((error) => { + console.error('Error cancelling agent:', error); + this.snackBar.open('Error cancelling agent', 'Close', { duration: 3000 }); + return of(null); + }) + ) + .subscribe((response) => { + if (response) { + this.snackBar.open('Agent cancelled successfully', 'Close', { duration: 3000 }); + // Optionally reload or update agent details + } + }); + } + + displayState(state: AgentRunningState): string { + switch (state) { + case 'agent': + return 'Agent control loop'; + case 'functions': + return 'Calling functions'; + case 'error': + return 'Error'; + case 'hil': + return 'Human-in-the-loop check'; + case 'feedback': + return 'Agent requested feedback'; + case 'completed': + return 'Completed'; + default: + return state; + } + } + + refreshAgentDetails(): void { + // Implement this method to refresh agent details + // You might need to emit an event to the parent component to handle this + } + + traceUrl(agent: AgentContext): string { + return `https://console.cloud.google.com/traces/list?referrer=search&project=${environment.gcpProject}&supportedpurview=project&pageState=(%22traceIntervalPicker%22:(%22groupValue%22:%22P1D%22,%22customValue%22:null))&tid=${agent.traceId}`; + } + + agentUrl(agent: AgentContext): string { + return `https://console.cloud.google.com/firestore/databases/${ + environment.firestoreDb || '(default)' + }/data/panel/AgentContext/${agent?.agentId}?project=${environment.gcpProject}`; + } + + getLlmName(llmId: string): string { + // Implement this method to get LLM name from ID + // You might need to inject a service that provides this information + return this.llmNameMap.get(llmId) || llmId; + } + + openFunctionEditModal(): void { + console.log('Opening function edit modal'); + console.log('Current functions:', this.agentDetails.functions); + console.log('All available functions:', this.allAvailableFunctions); + + const dialogRef = this.dialog.open(FunctionEditModalComponent, { + width: '400px', + data: { + functions: this.agentDetails.functions || [], // Ensure it's an array + allFunctions: this.allAvailableFunctions || [], // Ensure it's an array + }, + }); + + dialogRef.afterClosed().subscribe((result) => { + if (result) { + console.log('Dialog closed with result:', result); + this.saveFunctions(result); + } else { + console.log('Dialog closed without result'); + } + }); + } + + saveFunctions(selectedFunctions: string[]): void { + // this.isSavingFunctions = true; + this.http + .post(`${environment.serverUrl}agent/v1/update-functions`, { + agentId: this.agentDetails.agentId, + functions: selectedFunctions, + }) + .pipe( + catchError((error) => { + console.error('Error updating agent functions:', error); + this.snackBar.open('Error updating agent functions', 'Close', { duration: 3000 }); + return throwError(() => new Error('Error updating agent functions')); + }), + finalize(() => { + // this.isSavingFunctions = false; + }) + ) + .subscribe({ + next: () => { + this.snackBar.open('Agent functions updated successfully', 'Close', { duration: 3000 }); + this.agentDetails.functions = selectedFunctions; + this.changeDetectorRef.markForCheck(); + }, + }); + } + + openResumeModal(): void { + const dialogRef = this.dialog.open(ResumeAgentModalComponent, { + width: '500px', + }); + + dialogRef.afterClosed().subscribe((result) => { + if (result) { + this.resumeCompletedAgent(result.resumeInstructions); + } + }); + } + + private resumeCompletedAgent(resumeInstructions: string): void { + this.isSubmitting = true; + this.http + .post(`${environment.serverUrl}/agent/v1/resume-completed`, { + agentId: this.agentDetails.agentId, + executionId: this.agentDetails.executionId, + instructions: resumeInstructions, + }) + .pipe( + catchError((error) => { + console.error('Error resuming completed agent:', error); + this.snackBar.open('Error resuming completed agent', 'Close', { duration: 3000 }); + return of(null); + }), + finalize(() => { + this.isSubmitting = false; + }) + ) + .subscribe((response) => { + if (response) { + this.snackBar.open('Agent resumed successfully', 'Close', { duration: 3000 }); + // Optionally reload or update agent details + } + }); + } +} diff --git a/frontend/src/app/modules/agents/agent/agent-function-calls/agent-function-calls.component.ts b/frontend/src/app/modules/agents/agent/agent-function-calls/agent-function-calls.component.ts new file mode 100644 index 00000000..f698d53a --- /dev/null +++ b/frontend/src/app/modules/agents/agent/agent-function-calls/agent-function-calls.component.ts @@ -0,0 +1,37 @@ +import { Component, Input } from '@angular/core'; +import { AgentContext } from '../../agent.types'; +import { CommonModule } from '@angular/common'; +import { MatCardModule } from '@angular/material/card'; +import { MatExpansionModule } from '@angular/material/expansion'; + +@Component({ + selector: 'agent-function-calls', + template: ` + +
+
{{ invoked.function_name }}
+ +
+

{{ param.key }}: {{ param.value }}

+
+ + + Output + +

{{ invoked.stdout }}

+
+ + + Errors + +

{{ invoked.stderr }}

+
+
+
+ `, + standalone: true, + imports: [CommonModule, MatCardModule, MatExpansionModule], +}) +export class AgentFunctionCallsComponent { + @Input() agentDetails: AgentContext | null = null; +} diff --git a/frontend/src/app/modules/agents/agent/agent-llm-calls/agent-llm-calls.component.html b/frontend/src/app/modules/agents/agent/agent-llm-calls/agent-llm-calls.component.html new file mode 100644 index 00000000..177037a7 --- /dev/null +++ b/frontend/src/app/modules/agents/agent/agent-llm-calls/agent-llm-calls.component.html @@ -0,0 +1,98 @@ + +
+
+ + {{ call.callStack }} {{ call.description }} + + + storage + +
+ +
+ LLM: {{ getLlmName(call.llmId) }}    Request Time: + {{ call.requestTime | date : 'medium' }}.    Total Time: + {{ ((call.totalTime ?? 0) / 1000).toFixed(1) }}s   Tokens in/out: + {{ call.inputTokens }}/{{ call.outputTokens }}   Cost: ${{ + call.cost?.toFixed(4) + }} +
+ + + + + System Prompt: + + {{ call.systemPrompt | slice : 0 : 50 }} ... + + + +
{{ call.systemPrompt }}
+
+ + + + + Function Call History: + + {{ extractFunctionCallHistory(call.userPrompt) | slice : 0 : 150 }} ... + + + +
{{ extractFunctionCallHistory(call.userPrompt) }} +
+
+ + + + + Memory Contents: + + {{ extractMemoryContent(call.userPrompt) | slice : 0 : 150 }} + + + +
{{ extractMemoryContent(call.userPrompt) }}
+
+ + + + + User Prompt: + + {{ removeFunctionCallHistory(removeMemoryContent(call.userPrompt)) | slice : 0 : 150 }} ... + + + +
{{ removeFunctionCallHistory(removeMemoryContent(call.userPrompt)).trim() }}
+
+ + + + + Response Text: + + {{ call.responseText | slice : 0 : 150 }} ... + + + +
{{ call.responseText }}
+
+ +
+
+

No LLM calls found for this agent.

+
+
diff --git a/frontend/src/app/modules/agents/agent/agent-llm-calls/agent-llm-calls.component.scss b/frontend/src/app/modules/agents/agent/agent-llm-calls/agent-llm-calls.component.scss new file mode 100644 index 00000000..2fb7b9c1 --- /dev/null +++ b/frontend/src/app/modules/agents/agent/agent-llm-calls/agent-llm-calls.component.scss @@ -0,0 +1,4 @@ +.expansion-preview { + font-weight: normal; + font-size: smaller; +} \ No newline at end of file diff --git a/frontend/src/app/modules/agents/agent/agent-llm-calls/agent-llm-calls.component.ts b/frontend/src/app/modules/agents/agent/agent-llm-calls/agent-llm-calls.component.ts new file mode 100644 index 00000000..e1f05f8c --- /dev/null +++ b/frontend/src/app/modules/agents/agent/agent-llm-calls/agent-llm-calls.component.ts @@ -0,0 +1,107 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { LlmCall } from '../../agent.types'; +import { environment } from 'environments/environment'; +import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; +import { MatSnackBar } from '@angular/material/snack-bar'; +import { CommonModule } from '@angular/common'; +import { MatCardModule } from '@angular/material/card'; +import { MatIconModule } from '@angular/material/icon'; +import { MatExpansionModule } from '@angular/material/expansion'; +import { MatButtonModule } from '@angular/material/button'; + +@Component({ + selector: 'agent-llm-calls', + templateUrl: './agent-llm-calls.component.html', + styleUrl: 'agent-llm-calls.component.scss', + standalone: true, + imports: [ + CommonModule, + MatCardModule, + MatIconModule, + MatExpansionModule, + MatButtonModule, + ], +}) +export class AgentLlmCallsComponent implements OnInit { + @Input() agentId: string | null = null; + llmCalls: LlmCall[] = []; + + constructor( + private http: HttpClient, + private sanitizer: DomSanitizer, + private snackBar: MatSnackBar + ) {} + + ngOnInit(): void { + if (this.agentId) { + this.loadLlmCalls(); + } + } + + loadLlmCalls(): void { + this.http + .get(`${environment.apiBaseUrl}llms/calls/agent/${this.agentId}`) + .subscribe( + (calls) => { + this.llmCalls = calls.data; + this.llmCalls.forEach((call) => { + call.userPrompt = call.userPrompt.replace('\\n', '
'); + if (call.systemPrompt) { + call.systemPrompt = call.systemPrompt.replace('\\n', '
'); + } + }); + }, + (error) => { + console.error('Error loading LLM calls', error); + this.snackBar.open('Error loading LLM calls', 'Close', { + duration: 3000, + }); + } + ); + } + + removeFunctionCallHistory(text: string): string { + return text.replace(/.*?<\/function_call_history>/gs, ''); + } + + extractFunctionCallHistory(text: string): string | null { + const functionCallHistoryRegex = /(.*?)<\/function_call_history>/s; + const match = functionCallHistoryRegex.exec(text); + if (match && match[1]) { + return match[1].trim(); + } + return null; + } + + extractMemoryContent(text: string): string | null { + const memoryContentRegex = /(.*?)<\/memory>/s; + const match: RegExpExecArray | null = memoryContentRegex.exec(text); + if (match && match[0]) { + return match[0].trim(); + } + return null; + } + + removeMemoryContent(text: string): string { + return text.replace(/.*?<\/memory>/gs, ''); + } + + convertNewlinesToHtml(text: string): SafeHtml { + text ??= ''; + return this.sanitizer.bypassSecurityTrustHtml( + text.replaceAll('\\n', '
').replaceAll('\\t', '    ') + ); + } + + llmCallUrl(call: LlmCall): string { + return `https://console.cloud.google.com/firestore/databases/${ + environment.firestoreDb || '(default)' + }/data/panel/LlmCall/${call.id}?project=${environment.gcpProject}`; + } + + getLlmName(llmId: string): string { + // This method needs to be implemented or passed from the parent component + return llmId; + } +} diff --git a/frontend/src/app/modules/agents/agent/agent-memory/agent-memory.component.html b/frontend/src/app/modules/agents/agent/agent-memory/agent-memory.component.html new file mode 100644 index 00000000..a5c71f1f --- /dev/null +++ b/frontend/src/app/modules/agents/agent/agent-memory/agent-memory.component.html @@ -0,0 +1,14 @@ + +
+ + + + {{ entry.key }} + + +
{{ convertMemoryValue(entry.value) }}
+
+
+
diff --git a/frontend/src/app/modules/agents/agent/agent-memory/agent-memory.component.ts b/frontend/src/app/modules/agents/agent/agent-memory/agent-memory.component.ts new file mode 100644 index 00000000..7caf610a --- /dev/null +++ b/frontend/src/app/modules/agents/agent/agent-memory/agent-memory.component.ts @@ -0,0 +1,31 @@ +import { Component, Input } from '@angular/core'; +import { AgentContext } from '../../agent.types'; +import { MatCardModule } from '@angular/material/card'; +import { MatExpansionModule } from '@angular/material/expansion'; +import { NgForOf, NgIf, KeyValuePipe } from '@angular/common'; + +@Component({ + selector: 'agent-memory', + templateUrl: './agent-memory.component.html', + standalone: true, + imports: [ + MatCardModule, + MatExpansionModule, + NgForOf, + NgIf, + KeyValuePipe, + ], +}) +export class AgentMemoryComponent { + @Input() agentDetails!: AgentContext | null; + + convertMemoryValue(value: any): string { + return JSON.stringify(value, null, 2); + } + + memoryExpanded: { [key: string]: boolean } = {}; + + toggleExpansion(key: string): void { + this.memoryExpanded[key] = !this.memoryExpanded[key]; + } +} diff --git a/frontend/src/app/modules/agents/agent/agent.component.html b/frontend/src/app/modules/agents/agent/agent.component.html new file mode 100644 index 00000000..37564fe9 --- /dev/null +++ b/frontend/src/app/modules/agents/agent/agent.component.html @@ -0,0 +1,28 @@ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/frontend/src/app/modules/agents/agent/agent.component.ts b/frontend/src/app/modules/agents/agent/agent.component.ts new file mode 100644 index 00000000..a2edef39 --- /dev/null +++ b/frontend/src/app/modules/agents/agent/agent.component.ts @@ -0,0 +1,125 @@ +import {ChangeDetectionStrategy, Component, ViewEncapsulation, OnInit, ChangeDetectorRef} from '@angular/core'; +import { RouterOutlet } from '@angular/router'; +import { HttpClient } from '@angular/common/http'; +import { MatDialog } from '@angular/material/dialog'; +import { MatSnackBar } from '@angular/material/snack-bar'; +import { ActivatedRoute, Router } from '@angular/router'; +import { environment } from 'environments/environment'; +import { FunctionEditModalComponent } from './function-edit-modal/function-edit-modal.component'; +import { ResumeAgentModalComponent } from './resume-agent-modal/resume-agent-modal.component'; +import { FormBuilder, FormGroup } from '@angular/forms'; +import { MatTabsModule } from '@angular/material/tabs'; +import { MatCardModule } from '@angular/material/card'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { MatButtonModule } from '@angular/material/button'; +import { MatExpansionModule } from '@angular/material/expansion'; +import { MatListModule } from '@angular/material/list'; +import { MatIconModule } from '@angular/material/icon'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { CommonModule } from '@angular/common'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatSelectModule } from '@angular/material/select'; +import { AgentContext } from '../agent.types'; +import { MatDialogModule } from '@angular/material/dialog'; +import { AgentDetailsComponent } from './agent-details/agent-details.component'; +import { AgentMemoryComponent } from './agent-memory/agent-memory.component'; +import { AgentFunctionCallsComponent } from './agent-function-calls/agent-function-calls.component'; +import { AgentLlmCallsComponent } from './agent-llm-calls/agent-llm-calls.component'; + +@Component({ + selector: 'agent', + templateUrl: './agent.component.html', + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [ + RouterOutlet, + MatTabsModule, + MatCardModule, + MatFormFieldModule, + MatInputModule, + MatButtonModule, + MatExpansionModule, + MatListModule, + MatIconModule, + FormsModule, + ReactiveFormsModule, + CommonModule, + MatCheckboxModule, + MatSelectModule, + MatDialogModule, + AgentDetailsComponent, + AgentMemoryComponent, + AgentFunctionCallsComponent, + AgentLlmCallsComponent, + ], +}) +export class AgentComponent implements OnInit { + agentId: string | null = null; + agentDetails: AgentContext | null = null; + feedbackForm: FormGroup; + hilForm: FormGroup; + errorForm: FormGroup; + isSubmitting: boolean = false; + isResumingError: boolean = false; + + constructor( + private route: ActivatedRoute, + private http: HttpClient, + private formBuilder: FormBuilder, + private snackBar: MatSnackBar, + private router: Router, + private dialog: MatDialog, + private _changeDetectorRef: ChangeDetectorRef, + ) { + this.feedbackForm = this.formBuilder.group({ + feedback: [''], + }); + this.hilForm = this.formBuilder.group({ + feedback: [''], + }); + this.errorForm = this.formBuilder.group({ + errorDetails: [''], + }); + } + + ngOnInit(): void { + this.route.paramMap.subscribe(params => { + this.agentId = params.get('id'); + console.log(`agent.component ngOnInig ${this.agentId}`) + if (this.agentId) { + this.loadAgentDetails(this.agentId); + } + }); + } + + loadAgentDetails(agentId: string): void { + this.http.get(`${environment.apiBaseUrl}agent/v1/details/${agentId}`) + .subscribe( + details => { + this.agentDetails = (details as any).data; + + this.agentDetails.output = null; + if (this.agentDetails && this.agentDetails.state === 'completed') { + // If the agent has been cancelled after an error then display the error + // Otherwise display the Agent_completed argument + const maybeCompletedFunctionCall = this.agentDetails.functionCallHistory.length + ? this.agentDetails.functionCallHistory.slice(-1)[0] + : null; + if (maybeCompletedFunctionCall && maybeCompletedFunctionCall.parameters['note']) + this.agentDetails.output = this.agentDetails.error ?? maybeCompletedFunctionCall?.parameters['note'] ?? ''; + } + + console.log('Agent Details Loaded:', this.agentDetails); + this._changeDetectorRef.markForCheck(); + }, + error => { + console.error('Error loading agent details', error); + this.snackBar.open('Error loading agent details', 'Close', { duration: 3000 }); + } + ); + } + + // Add other methods as needed (e.g., onSubmitFeedback, onResumeHil, cancelAgent, etc.) +} diff --git a/frontend/src/app/agent/function-edit-modal/function-edit-modal.component.html b/frontend/src/app/modules/agents/agent/function-edit-modal/function-edit-modal.component.html similarity index 100% rename from frontend/src/app/agent/function-edit-modal/function-edit-modal.component.html rename to frontend/src/app/modules/agents/agent/function-edit-modal/function-edit-modal.component.html diff --git a/frontend/src/app/agent/function-edit-modal/function-edit-modal.component.scss b/frontend/src/app/modules/agents/agent/function-edit-modal/function-edit-modal.component.scss similarity index 100% rename from frontend/src/app/agent/function-edit-modal/function-edit-modal.component.scss rename to frontend/src/app/modules/agents/agent/function-edit-modal/function-edit-modal.component.scss diff --git a/frontend/src/app/agent/function-edit-modal/function-edit-modal.component.ts b/frontend/src/app/modules/agents/agent/function-edit-modal/function-edit-modal.component.ts similarity index 53% rename from frontend/src/app/agent/function-edit-modal/function-edit-modal.component.ts rename to frontend/src/app/modules/agents/agent/function-edit-modal/function-edit-modal.component.ts index 2cff7ce0..a7499ccd 100644 --- a/frontend/src/app/agent/function-edit-modal/function-edit-modal.component.ts +++ b/frontend/src/app/modules/agents/agent/function-edit-modal/function-edit-modal.component.ts @@ -1,10 +1,29 @@ import { Component, Inject } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MatDialogModule } from '@angular/material/dialog'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { MatListModule } from '@angular/material/list'; +import { MatIconModule } from '@angular/material/icon'; @Component({ selector: 'app-function-edit-modal', templateUrl: './function-edit-modal.component.html', styleUrls: ['./function-edit-modal.component.scss'], + standalone: true, + imports: [ + CommonModule, + FormsModule, + MatButtonModule, + MatDialogModule, + MatFormFieldModule, + MatInputModule, + MatListModule, + MatIconModule, + ], }) export class FunctionEditModalComponent { allFunctions: string[]; @@ -15,9 +34,11 @@ export class FunctionEditModalComponent { private dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) data: { functions: string[]; allFunctions: string[] } ) { - // Sort all functions and selected functions alphabetically - this.allFunctions = data.allFunctions.sort(); - this.selectedFunctions = [...data.functions].sort(); + console.log('Received data:', data); + this.allFunctions = (data.allFunctions || []).sort(); + this.selectedFunctions = [...(data.functions || [])].sort(); + console.log('Initialized allFunctions:', this.allFunctions); + console.log('Initialized selectedFunctions:', this.selectedFunctions); } filterFunctions(): string[] { @@ -36,9 +57,11 @@ export class FunctionEditModalComponent { this.selectedFunctions.push(func); this.selectedFunctions.sort(); } + console.log('Updated selectedFunctions:', this.selectedFunctions); } onSave(): void { + console.log('Saving selectedFunctions:', this.selectedFunctions); this.dialogRef.close(this.selectedFunctions); } diff --git a/frontend/src/app/modules/agents/agent/resume-agent-modal/resume-agent-modal.component.ts b/frontend/src/app/modules/agents/agent/resume-agent-modal/resume-agent-modal.component.ts new file mode 100644 index 00000000..fcda6f2f --- /dev/null +++ b/frontend/src/app/modules/agents/agent/resume-agent-modal/resume-agent-modal.component.ts @@ -0,0 +1,55 @@ +import { Component, OnInit } from '@angular/core'; +import { MatDialogRef, MatDialogModule } from '@angular/material/dialog'; +import { MatButtonModule } from '@angular/material/button'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms'; +import { CommonModule } from '@angular/common'; + +@Component({ + selector: 'app-resume-agent-modal', + template: ` +

Resume Agent

+
+ + + Resume Instructions + + + Resume instructions are required + + + + + + + +
+ `, + standalone: true, + imports: [CommonModule, MatDialogModule, MatButtonModule, MatFormFieldModule, MatInputModule, ReactiveFormsModule], +}) +export class ResumeAgentModalComponent implements OnInit { + resumeForm: FormGroup; + + constructor( + public dialogRef: MatDialogRef, + private fb: FormBuilder + ) { + this.resumeForm = this.fb.group({ + resumeInstructions: ['', Validators.required] + }); + } + + ngOnInit(): void {} + + onNoClick(): void { + this.dialogRef.close(); + } + + onSubmit(): void { + if (this.resumeForm.valid) { + this.dialogRef.close(this.resumeForm.value); + } + } +} diff --git a/frontend/src/app/modules/agents/new-agent/new-agent.component.html b/frontend/src/app/modules/agents/new-agent/new-agent.component.html new file mode 100644 index 00000000..96ec604d --- /dev/null +++ b/frontend/src/app/modules/agents/new-agent/new-agent.component.html @@ -0,0 +1,114 @@ +
+ +
+
+ +
+ New Autonomous Agent +
+ +
+ + + Name + + + + + + Function calling type + + Code Generation + XML + Native + + + + + + Prompt + + + + + +
+

LLMs

+
+ +
+ + Easy + + @for (llm of llms; track llm.id) { + {{ llm.name }} + } + + + + Medium + + @for (llm of llms; track llm.id) { + {{ llm.name }} + } + + + + Hard + + @for (llm of llms; track llm.id) { + {{ llm.name }} + } + + +
+ + + + + +
+

Functions

+
+ +
+ @for (func of functions; track func) { + {{ func }} + } +
+ + +
+

Human In The Loop

+
+ +
+ + Budget $USD + + + + Agent control loop iterations + + +
+ + +
+ +
+
+
+
+
diff --git a/frontend/src/app/modules/agents/new-agent/new-agent.component.ts b/frontend/src/app/modules/agents/new-agent/new-agent.component.ts new file mode 100644 index 00000000..70f03f27 --- /dev/null +++ b/frontend/src/app/modules/agents/new-agent/new-agent.component.ts @@ -0,0 +1,186 @@ +import { TextFieldModule } from '@angular/cdk/text-field'; +import { NgClass } from '@angular/common'; +import {Component, OnInit, ViewEncapsulation} from '@angular/core'; +import { + FormControl, FormGroup, + FormsModule, + ReactiveFormsModule, + UntypedFormBuilder, + Validators, +} from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MatButtonToggleModule } from '@angular/material/button-toggle'; +import { MatChipsModule } from '@angular/material/chips'; +import { MatOptionModule } from '@angular/material/core'; +import { MatDatepickerModule } from '@angular/material/datepicker'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatSelectModule } from '@angular/material/select'; +import { HttpClient } from "@angular/common/http"; +import { MatSnackBar } from "@angular/material/snack-bar"; +import { Router } from "@angular/router"; +import { LlmService } from "../services/llm.service"; +import { map } from "rxjs"; +import { MatProgressSpinner } from "@angular/material/progress-spinner"; +import { MatCheckboxModule } from "@angular/material/checkbox"; + +interface StartAgentResponse { + data: { + agentId: string; + }; +} + +const defaultType/*: AgentType*/ = 'codegen'; + +@Component({ + selector: 'new-agent', + templateUrl: './new-agent.component.html', + encapsulation: ViewEncapsulation.None, + standalone: true, + imports: [ + MatIconModule, + FormsModule, + MatFormFieldModule, + NgClass, + MatInputModule, + TextFieldModule, + ReactiveFormsModule, + MatButtonToggleModule, + MatButtonModule, + MatSelectModule, + MatOptionModule, + MatCheckboxModule, + MatChipsModule, + MatDatepickerModule, + MatProgressSpinner, + ], +}) +export class NewAgentComponent implements OnInit { + functions: string[] = []; + llms: any[] = []; + runAgentForm: FormGroup; + isSubmitting: boolean = false; + + constructor( + private http: HttpClient, + private snackBar: MatSnackBar, + private router: Router, + // private agentEventService: AgentEventService, + private llmService: LlmService + ) { + this.runAgentForm = new FormGroup({ + name: new FormControl('', Validators.required), + userPrompt: new FormControl('', Validators.required), + type: new FormControl(defaultType, Validators.required), + llmEasy: new FormControl('', Validators.required), + llmMedium: new FormControl('', Validators.required), + llmHard: new FormControl('', Validators.required), + budget: new FormControl(0, [Validators.required, Validators.min(0)]), + count: new FormControl(0, [Validators.required, Validators.min(0), Validators.pattern('^[0-9]*$')]), + }); + } + setPreset(preset: string): boolean { + console.log(`setPreset ${preset}`); + const presets = { + 'claude-vertex': { + easy: 'anthropic-vertex:claude-3-haiku', + medium: 'anthropic-vertex:claude-3-5-sonnet', + hard: 'anthropic-vertex:claude-3-5-sonnet', + }, + claude: { + easy: 'anthropic:claude-3-haiku', + medium: 'anthropic:claude-3-5-sonnet', + hard: 'anthropic:claude-3-5-sonnet', + }, + gemini: { easy: 'vertex:gemini-1.5-flash', medium: 'vertex:gemini-1.5-flash', hard: 'vertex:gemini-1.5-pro' }, + openai: { easy: 'openai:gpt-4o', medium: 'openai:gpt-4o', hard: 'openai:gpt-4o' }, + }; + const selection = presets[preset]; + if (selection) { + const ids = this.llms.map((llm) => llm.id); + this.runAgentForm.controls['llmEasy'].setValue(ids.find((id) => id.startsWith(selection.easy))); + this.runAgentForm.controls['llmMedium'].setValue(ids.find((id) => id.startsWith(selection.medium))); + this.runAgentForm.controls['llmHard'].setValue(ids.find((id) => id.startsWith(selection.hard))); + } + return false; + } + + ngOnInit(): void { + this.http + .get<{ data: string[] }>(`http://localhost:3000/api/agent/v1/functions`) + .pipe( + map((response) => { + console.log(response); + return (response.data as string[]).filter((name) => name !== 'Agent'); + }) + ) + .subscribe((functions) => { + this.functions = functions.sort(); + // Dynamically add form controls for each function + functions.forEach((tool, index) => { + (this.runAgentForm as FormGroup).addControl('function' + index, new FormControl(false)); + }); + }); + + this.llmService.getLlms().subscribe({ + next: (llms) => { + this.llms = llms; + }, + error: (error) => { + console.error('Error fetching LLMs:', error); + this.snackBar.open('Failed to load LLMs', 'Close', { duration: 3000 }); + }, + }); + + this.loadUserProfile(); + } + + private loadUserProfile(): void { + const profileUrl = `http://localhost:3000/api/profile/view`; + this.http.get(profileUrl).subscribe( + (response: any) => { + console.log(response.data); + this.runAgentForm.controls['budget'].setValue(response.data.hilBudget); + this.runAgentForm.controls['count'].setValue(response.data.hilCount); + }, + (error) => { + console.log(error); + this.snackBar.open('Failed to load user profile', 'Close', { duration: 3000 }); + } + ); + } + + // ... rest of the component + onSubmit(): void { + if (!this.runAgentForm.valid) return; + // Implement the logic to handle form submission + console.log('Form submitted', this.runAgentForm.value); + const selectedFunctions: string[] = this.functions + .filter((_, index) => this.runAgentForm.value['function' + index]) + .map((tool, _) => tool); + this.http + .post(`http://localhost:3000/api/agent/v1/start`, { + name: this.runAgentForm.value.name, + userPrompt: this.runAgentForm.value.userPrompt, + type: this.runAgentForm.value.type, + // systemPrompt: this.runAgentForm.value.systemPrompt, + functions: selectedFunctions, + budget: this.runAgentForm.value.budget, + count: this.runAgentForm.value.count, + llmEasy: this.runAgentForm.value.llmEasy, + llmMedium: this.runAgentForm.value.llmMedium, + llmHard: this.runAgentForm.value.llmHard, + }) + .subscribe({ + next: (response) => { + this.snackBar.open('Agent started', 'Close', { duration: 3000 }); + this.router.navigate(['/agent', response.data.agentId]).catch((e) => console.error); // Assuming the response contains the agentId + }, + error: (error) => { + this.snackBar.open(`Error ${error.message}`, 'Close', { duration: 3000 }); + console.error('Error starting agent', error); + }, + }); + } +} diff --git a/frontend/src/app/modules/agents/services/agent.service.ts b/frontend/src/app/modules/agents/services/agent.service.ts new file mode 100644 index 00000000..a9a549a4 --- /dev/null +++ b/frontend/src/app/modules/agents/services/agent.service.ts @@ -0,0 +1,67 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { BehaviorSubject, Observable, tap } from 'rxjs'; +import { AgentContext, AgentPagination, LlmCall } from '../agent.types'; +import { environment } from 'environments/environment'; + +@Injectable({ providedIn: 'root' }) +export class AgentService { + private _agents: BehaviorSubject = new BehaviorSubject(null); + + private _pagination: BehaviorSubject = + new BehaviorSubject({ + length: 0, + size: 0, + endIndex: 0, + page: 0, + lastPage: 0, + startIndex: 0 + }); + + constructor(private _httpClient: HttpClient) {} + + get agents$(): Observable { + return this._agents.asObservable(); + } + + get pagination$(): Observable { + return this._pagination.asObservable(); + } + + getAgents(): Observable { + return this._httpClient.get(`${environment.apiBaseUrl}agent/v1/list`).pipe( + tap((agents) => { + agents = (agents as any).data; + this._agents.next(agents); + }) + ); + } + + getAgentDetails(agentId: string): Observable { + return this._httpClient.get(`${environment.apiBaseUrl}agent/v1/details/${agentId}`); + } + + getLlmCalls(agentId: string): Observable { + return this._httpClient.get(`${environment.apiBaseUrl}llms/calls/agent/${agentId}`); + } + + submitFeedback(agentId: string, executionId: string, feedback: string): Observable { + return this._httpClient.post(`${environment.apiBaseUrl}agent/v1/feedback`, { agentId, executionId, feedback }); + } + + resumeAgent(agentId: string, executionId: string, feedback: string): Observable { + return this._httpClient.post(`${environment.apiBaseUrl}agent/v1/resume-hil`, { agentId, executionId, feedback }); + } + + cancelAgent(agentId: string, executionId: string, reason: string): Observable { + return this._httpClient.post(`${environment.apiBaseUrl}agent/v1/cancel`, { agentId, executionId, reason }); + } + + updateAgentFunctions(agentId: string, functions: string[]): Observable { + return this._httpClient.post(`${environment.apiBaseUrl}agent/v1/update-functions`, { agentId, functions }); + } + + deleteAgents(agentIds: string[]): Observable { + return this._httpClient.post(`${environment.apiBaseUrl}agent/v1/delete`, { agentIds }); + } +} diff --git a/frontend/src/app/modules/agents/services/function.service.ts b/frontend/src/app/modules/agents/services/function.service.ts new file mode 100644 index 00000000..d50864f8 --- /dev/null +++ b/frontend/src/app/modules/agents/services/function.service.ts @@ -0,0 +1,49 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpErrorResponse } from '@angular/common/http'; +import { Observable, BehaviorSubject, throwError } from 'rxjs'; +import { tap, shareReplay, map, catchError, retry } from 'rxjs/operators'; +import {environment} from "../../../../environments/environment"; + +@Injectable({ + providedIn: 'root', +}) +export class FunctionsService { + private functionsSubject = new BehaviorSubject([]); + private functionsLoaded = false; + + constructor(private http: HttpClient) {} + + getFunctions(): Observable { + if (!this.functionsLoaded) { + return this.fetchFunctions().pipe( + tap((llms) => { + this.functionsSubject.next(llms); + this.functionsLoaded = true; + }), + shareReplay(1) + ); + } + return this.functionsSubject.asObservable(); + } + + private fetchFunctions(): Observable { + return this.http.get<{ data: string[] }>(`${environment.apiBaseUrl}agent/v1/functions`).pipe( + retry(3), + map((response) => response.data), + catchError(this.handleError) + ); + } + + private handleError(error: HttpErrorResponse) { + let errorMessage = 'An error occurred'; + if (error.error instanceof ErrorEvent) { + // Client-side error + errorMessage = `Error: ${error.error.message}`; + } else { + // Server-side error + errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`; + } + console.error(errorMessage); + return throwError(() => new Error(errorMessage)); + } +} diff --git a/frontend/src/app/shared/services/llm.service.spec.ts b/frontend/src/app/modules/agents/services/llm.service.spec.ts similarity index 93% rename from frontend/src/app/shared/services/llm.service.spec.ts rename to frontend/src/app/modules/agents/services/llm.service.spec.ts index 012aa59a..b94580e5 100644 --- a/frontend/src/app/shared/services/llm.service.spec.ts +++ b/frontend/src/app/modules/agents/services/llm.service.spec.ts @@ -1,9 +1,10 @@ import { TestBed } from '@angular/core/testing'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { LlmService, LLM } from './llm.service'; -import { environment } from '@env/environment'; +import {environment} from "../../../../environments/environment"; -const LLM_LIST_API_URL = `${environment.serverUrl}/llms/list`; + +const LLM_LIST_API_URL = `${environment.serverUrl}llms/list`; describe('LlmService', () => { let service: LlmService; diff --git a/frontend/src/app/shared/services/llm.service.ts b/frontend/src/app/modules/agents/services/llm.service.ts similarity index 89% rename from frontend/src/app/shared/services/llm.service.ts rename to frontend/src/app/modules/agents/services/llm.service.ts index fdd08e14..05a6bc43 100644 --- a/frontend/src/app/shared/services/llm.service.ts +++ b/frontend/src/app/modules/agents/services/llm.service.ts @@ -2,8 +2,8 @@ import { Injectable } from '@angular/core'; import { HttpClient, HttpErrorResponse } from '@angular/common/http'; import { Observable, BehaviorSubject, throwError } from 'rxjs'; import { tap, shareReplay, map, catchError, retry } from 'rxjs/operators'; -import { environment } from '@env/environment'; -import { CredentialsService } from '@app/auth'; +import {environment} from "../../../../environments/environment"; + export interface LLM { id: string; @@ -34,7 +34,7 @@ export class LlmService { } private fetchLlms(): Observable { - return this.http.get<{ data: LLM[] }>(`${environment.serverUrl}/llms/list`).pipe( + return this.http.get<{ data: LLM[] }>(`${environment.apiBaseUrl}llms/list`).pipe( map((response) => response.data), retry(3), catchError(this.handleError) diff --git a/frontend/src/app/modules/assistants/assistant-info/assistant-info.component.html b/frontend/src/app/modules/assistants/assistant-info/assistant-info.component.html new file mode 100644 index 00000000..b663394a --- /dev/null +++ b/frontend/src/app/modules/assistants/assistant-info/assistant-info.component.html @@ -0,0 +1,73 @@ +
+ +
+ +
Chat info
+
+ +
+
+ + +
+
+
diff --git a/frontend/src/app/modules/assistants/assistant-info/assistant-info.component.ts b/frontend/src/app/modules/assistants/assistant-info/assistant-info.component.ts new file mode 100644 index 00000000..057c2e03 --- /dev/null +++ b/frontend/src/app/modules/assistants/assistant-info/assistant-info.component.ts @@ -0,0 +1,28 @@ +import { + ChangeDetectionStrategy, + Component, + Input, + ViewEncapsulation, +} from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatDrawer } from '@angular/material/sidenav'; +import { AssistantChat } from 'app/modules/assistants/assistant.types'; + +@Component({ + selector: 'chat-info', + templateUrl: './assistant-info.component.html', + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [MatButtonModule, MatIconModule], +}) +export class AssistantInfoComponent { + @Input() chat: AssistantChat; + @Input() drawer: MatDrawer; + + /** + * Constructor + */ + constructor() {} +} diff --git a/frontend/src/app/modules/assistants/assistant.routes.ts b/frontend/src/app/modules/assistants/assistant.routes.ts new file mode 100644 index 00000000..b7f59c83 --- /dev/null +++ b/frontend/src/app/modules/assistants/assistant.routes.ts @@ -0,0 +1,78 @@ +import { inject } from '@angular/core'; +import { + ActivatedRouteSnapshot, + Router, + RouterStateSnapshot, + Routes, +} from '@angular/router'; +import { AssistantsComponent } from 'app/modules/assistants/assistants.component'; +import { AssistantsService } from 'app/modules/assistants/assistants.service'; +import { AssistantListComponent } from 'app/modules/assistants/chats/assistant-list.component'; +import { AssistantComponent } from 'app/modules/assistants/assistant/assistant.component'; +import { EmptyAssistantComponent } from 'app/modules/assistants/empty-assistant/empty-assistant.component'; +import { catchError, throwError } from 'rxjs'; + +/** + * Conversation resolver + * + * @param route + * @param state + */ +const conversationResolver = ( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot +) => { + const chatService = inject(AssistantsService); + const router = inject(Router); + + return chatService.getChatById(route.paramMap.get('id')).pipe( + // Error here means the requested chat is not available + catchError((error) => { + // Log the error + console.error(error); + + // Get the parent url + const parentUrl = state.url.split('/').slice(0, -1).join('/'); + + // Navigate to there + router.navigateByUrl(parentUrl); + + // Throw an error + return throwError(error); + }) + ); +}; + +export default [ + { + path: '', + component: AssistantsComponent, + resolve: { + chats: () => inject(AssistantsService).getChats(), + }, + children: [ + { + path: '', + component: AssistantListComponent, + children: [ + { + path: '', + pathMatch: 'full', + component: EmptyAssistantComponent, + }, + { + path: 'new', + component: AssistantComponent, + }, + { + path: ':id', + component: AssistantComponent, + resolve: { + conversation: conversationResolver, + }, + }, + ], + }, + ], + }, +] as Routes; diff --git a/frontend/src/app/modules/assistants/assistant.types.ts b/frontend/src/app/modules/assistants/assistant.types.ts new file mode 100644 index 00000000..91f03fd3 --- /dev/null +++ b/frontend/src/app/modules/assistants/assistant.types.ts @@ -0,0 +1,28 @@ + +export interface LlmMessage { + role: 'system' | 'user' | 'assistant'; + text: string; + /** The LLM which generated the text (only when role=assistant) */ + llmId?: string; + /** Set the cache_control flag with Claude models */ + cache?: 'ephemeral'; + time?: number; +} + +export interface AssistantChat { + id: string; + title: string; + contactId?: string; + unreadCount?: number; + lastMessage?: string; + lastMessageAt?: string; + messages?: { + id?: string; + chatId?: string; + contactId?: string; + isMine?: boolean; + value?: string; + llmId?: string; + createdAt?: string; + }[]; +} diff --git a/frontend/src/app/modules/assistants/assistant/assistant.component.html b/frontend/src/app/modules/assistants/assistant/assistant.component.html new file mode 100644 index 00000000..10bfe681 --- /dev/null +++ b/frontend/src/app/modules/assistants/assistant/assistant.component.html @@ -0,0 +1,242 @@ +
+ @if (chat) { + + + + + + + + + + +
+ + + + + + + + + +
+ + +
+
+ @for ( + message of chat.messages; + track trackByFn(i, message); + let i = $index; + let first = $first; + let last = $last + ) { + +
+ +
+ + @if ( + last || + chat.messages[i + 1].isMine !== + message.isMine + ) { +
+ +
+ } + +
+ +
+
+ + @if ( + first || + last || + chat.messages[i + 1].isMine !== + message.isMine || + chat.messages[i + 1].createdAt !== + message.createdAt + ) { +
+ {{ message.createdAt | date: 'HH:mm' }} +
+ } +
+ } +
+
+ + +
+ +
+ +
+ + +
+ + + + @for (llm of $llms | async; track llm.id) { + + {{ llm.name }} + + } + + +
+ + + + + +
+ +
+
+
+
+ } @else { +
+ +
+ Start a new chat +
+
+ } + + + + + + + + + + + + +
diff --git a/frontend/src/app/modules/assistants/assistant/assistant.component.scss b/frontend/src/app/modules/assistants/assistant/assistant.component.scss new file mode 100644 index 00000000..90cad33b --- /dev/null +++ b/frontend/src/app/modules/assistants/assistant/assistant.component.scss @@ -0,0 +1,28 @@ +.chat-row { + position: relative; + display: flex; + align-items: center; + padding: 8px; + + &:hover { + background-color: #f5f5f5; + } + + .chat-row-content { + flex: 1; + } + + .delete-button { + position: absolute; + right: 8px; + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + transition: opacity 0.2s; + } + + &:hover .delete-button { + opacity: 1; + } +} diff --git a/frontend/src/app/modules/assistants/assistant/assistant.component.ts b/frontend/src/app/modules/assistants/assistant/assistant.component.ts new file mode 100644 index 00000000..a0e3fada --- /dev/null +++ b/frontend/src/app/modules/assistants/assistant/assistant.component.ts @@ -0,0 +1,298 @@ +import { TextFieldModule } from '@angular/cdk/text-field'; +import {AsyncPipe, DatePipe, NgClass, NgTemplateOutlet} from '@angular/common'; +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + ElementRef, + HostListener, + NgZone, + OnDestroy, + OnInit, + ViewChild, + ViewEncapsulation, +} from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatSidenavModule } from '@angular/material/sidenav'; +import {Router, RouterLink, RouterModule, ActivatedRoute} from '@angular/router'; +import { FuseMediaWatcherService } from '@fuse/services/media-watcher'; +import { AssistantsService } from 'app/modules/assistants/assistants.service'; +import { AssistantChat } from '../assistant.types'; +import { AssistantInfoComponent } from 'app/modules/assistants/assistant-info/assistant-info.component'; +import { LLM, LlmService } from "app/modules/agents/services/llm.service"; +import {BehaviorSubject, Observable, Subject, takeUntil} from 'rxjs'; +import { + CLIPBOARD_OPTIONS, + ClipboardButtonComponent, + MarkdownModule, + MarkdownService, + provideMarkdown +} from "ngx-markdown"; +import {MatOption} from "@angular/material/core"; +import {MatSelect} from "@angular/material/select"; +import {ReactiveFormsModule} from "@angular/forms"; + + +@Component({ + selector: 'chat-conversation', + templateUrl: './assistant.component.html', + styleUrls: ['./assistant.component.scss'], + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [ + MatSidenavModule, + AssistantInfoComponent, + MatButtonModule, + RouterLink, + MatIconModule, + MatMenuModule, + MatButtonModule, + MatMenuModule, + NgClass, + NgTemplateOutlet, + MatFormFieldModule, + MatInputModule, + TextFieldModule, + DatePipe, + MarkdownModule, + AsyncPipe, + RouterModule, + MatOption, + MatSelect, + ReactiveFormsModule, + ], + providers: [ + provideMarkdown({ + clipboardOptions: { + provide: CLIPBOARD_OPTIONS, + useValue: { + buttonComponent: ClipboardButtonComponent, + }, + }, + }) + ] +}) +export class AssistantComponent implements OnInit, OnDestroy { + + @ViewChild('messageInput') messageInput: ElementRef; + chat: AssistantChat; + drawerMode: 'over' | 'side' = 'side'; + drawerOpened: boolean = false; + private _unsubscribeAll: Subject = new Subject(); + $llms: BehaviorSubject = new BehaviorSubject(null); + llmId: string; + sendIcon: string = 'heroicons_outline:paper-airplane' + + /** + * Constructor + */ + constructor( + private _changeDetectorRef: ChangeDetectorRef, + private _assistantService: AssistantsService, + private _fuseMediaWatcherService: FuseMediaWatcherService, + private _ngZone: NgZone, + private _elementRef: ElementRef, + private _markdown: MarkdownService, + private llmService: LlmService, + private router: Router, + private route: ActivatedRoute + ) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Decorated methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Resize on 'input' and 'ngModelChange' events + * + * @private + */ + @HostListener('input') + @HostListener('ngModelChange') + private _resizeMessageInput(): void { + // This doesn't need to trigger Angular's change detection by itself + this._ngZone.runOutsideAngular(() => { + setTimeout(() => { + // Set the height to 'auto' so we can correctly read the scrollHeight + this.messageInput.nativeElement.style.height = 'auto'; + + // Detect the changes so the height is applied + this._changeDetectorRef.detectChanges(); + + // Get the scrollHeight and subtract the vertical padding + this.messageInput.nativeElement.style.height = `${this.messageInput.nativeElement.scrollHeight}px`; + + // Detect the changes one more time to apply the final height + this._changeDetectorRef.detectChanges(); + }); + }); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Subscribe to route parameters + this.route.params + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(params => { + const chatId = params['id']; + + if (chatId === 'new' || !chatId) { + // If 'new' or no ID, reset the chat + this.resetChat(); + } else { + // Load the chat by ID + this._assistantService.getChatById(chatId).subscribe(); + } + }); + + // Chat observable + this._assistantService.chat$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((chat: AssistantChat) => { + this.chat = chat || { id: '', messages: [], title: '' }; + if(chat.messages.length > 0) { + const lastMessageLlmId = chat.messages.at(-1).llmId + if (lastMessageLlmId) { + this.llmId = lastMessageLlmId; + console.log(`last message llm ${this.llmId}`) + } else { + // TODO default to user profile default chat LLM + } + } + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + + // Media watcher (unchanged) + this._fuseMediaWatcherService.onMediaChange$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(({ matchingAliases }) => { + this.drawerMode = matchingAliases.includes('lg') ? 'side' : 'over'; + this._changeDetectorRef.markForCheck(); + }); + + // Load LLMs (unchanged) + this.llmService.getLlms().subscribe(llms => this.$llms.next(llms)); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Open the contact info + */ + openChatInfo(): void { + // Open the drawer + this.drawerOpened = true; + + // Mark for check + this._changeDetectorRef.markForCheck(); + } + + /** + * Reset the chat + */ + resetChat(): void { + const newChat: AssistantChat = { id: '', messages: [], title: '' }; + this.chat = newChat; + this._assistantService.resetChat(); + + // TODO set LLM field to the user profile default chat LLM + + // Close the contact info in case it's opened + this.drawerOpened = false; + + // Clear the input field + if (this.messageInput) { + this.messageInput.nativeElement.value = ''; + } + + // Mark for check + this._changeDetectorRef.markForCheck(); + } + + /** + * Delete the current chat + */ + deleteChat(): void { + if (this.chat && this.chat.id) { + this._assistantService.deleteChat(this.chat.id).subscribe(() => { + this.resetChat(); + this.router.navigate(['/apps/chat']).catch(console.error); + }); + } + } + + /** + * Track by function for ngFor loops + * + * @param index + * @param item + */ + trackByFn(index: number, item: any): any { + return item.id || index; + } + + sendMessage(): void { + const message = this.messageInput.nativeElement.value.trim(); + if (message === '') { + return; + } + + // If this is a new chat, then redirect to the created chat + if (!this.chat.id) { + this.chat.messages.push({ + value: message, + isMine: true, + }) + this.messageInput.nativeElement.value = ''; + this._changeDetectorRef.markForCheck(); + // TODO handle error, set the message back to the messageInput and remove from chat.messages + this._assistantService.createChat(message, this.llmId).subscribe(async (chat: AssistantChat) => { + this.router.navigate([`/apps/chat/${chat.id}`]).catch(console.error); + }); + + return; + } + + this.sendIcon = 'heroicons_outline:stop-circle' + this._assistantService.sendMessage(this.chat.id, message, this.llmId).subscribe(() => { + this.sendIcon = 'heroicons_outline:paper-airplane' + // Clear the input + this.messageInput.nativeElement.value = ''; + this._resizeMessageInput(); + this._scrollToBottom(); + + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + } + + private _scrollToBottom(): void { + setTimeout(() => { + const chatElement = this._elementRef.nativeElement.querySelector('.conversation-container'); + chatElement.scrollTop = chatElement.scrollHeight; + }); + } +} diff --git a/frontend/src/app/modules/assistants/assistants.component.html b/frontend/src/app/modules/assistants/assistants.component.html new file mode 100644 index 00000000..9c7107f0 --- /dev/null +++ b/frontend/src/app/modules/assistants/assistants.component.html @@ -0,0 +1,6 @@ +
+ +
+ +
+
diff --git a/frontend/src/app/modules/assistants/assistants.component.ts b/frontend/src/app/modules/assistants/assistants.component.ts new file mode 100644 index 00000000..1f239036 --- /dev/null +++ b/frontend/src/app/modules/assistants/assistants.component.ts @@ -0,0 +1,21 @@ +import { + ChangeDetectionStrategy, + Component, + ViewEncapsulation, +} from '@angular/core'; +import { RouterOutlet } from '@angular/router'; + +@Component({ + selector: 'chat', + templateUrl: './assistants.component.html', + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [RouterOutlet], +}) +export class AssistantsComponent { + /** + * Constructor + */ + constructor() {} +} diff --git a/frontend/src/app/modules/assistants/assistants.service.ts b/frontend/src/app/modules/assistants/assistants.service.ts new file mode 100644 index 00000000..b1f72256 --- /dev/null +++ b/frontend/src/app/modules/assistants/assistants.service.ts @@ -0,0 +1,275 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { AssistantChat, LlmMessage } from 'app/modules/assistants/assistant.types'; +import { + BehaviorSubject, + Observable, + filter, + map, + of, + switchMap, + take, + tap, + throwError, +} from 'rxjs'; + +@Injectable({ providedIn: 'root' }) +export class AssistantsService { + private _chat: BehaviorSubject = new BehaviorSubject(null); + private _chats: BehaviorSubject = new BehaviorSubject(null); + + /** + * Constructor + */ + constructor(private _httpClient: HttpClient) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Getter for chat + */ + get chat$(): Observable { + return this._chat.asObservable(); + } + + /** + * Getter for chats + */ + get chats$(): Observable { + return this._chats.asObservable(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Get chats + */ + getChats(): Observable { + return this._httpClient.get('/api/chats').pipe( + tap((response: AssistantChat[]) => { + response = (response as any).data.chats + this._chats.next(response); + }) + ); + } + + createChat(message: string, llmId: string): Observable { + return this._httpClient.post('/api/chat/new', { text: message, llmId }).pipe( + map((response: any) => { + const newChat: AssistantChat = response.data; + const currentChats = this._chats.value || []; + this._chats.next([newChat, ...currentChats]); + return newChat; + }) + ); + } + + deleteChat(chatId: string): Observable { + return this._httpClient.delete(`/api/chat/${chatId}`).pipe( + tap(() => { + const currentChats = this._chats.value || []; + this._chats.next(currentChats.filter(chat => chat.id !== chatId)); + }) + ); + } + + /** + * Get chat + * + * @param id + */ + getChatById(id: string): Observable { + if(!id?.trim()) { + console.log(`nullish chat id "${id}"`) + const chat: AssistantChat = {messages:[], id: null, title: ''} + this._chat.next(chat); + return this._chats + } + return this._httpClient + .get(`api/chat/${id}`) + .pipe( + map((chat: AssistantChat) => { + // Update the chat + chat = (chat as any).data + + chat = { + id: chat.id, + lastMessage: (chat.messages[chat.messages.length - 1] as any).text, + title: chat.title, + messages: chat.messages.map(msg => { + const llmMsg = msg as LlmMessage + return { + ...msg, + value: llmMsg.text, + isMine: llmMsg.role === 'user' + } + }) + } + console.log(chat) + this._chat.next(chat); + + // Return the chat + return chat; + }), + switchMap((chat: AssistantChat) => { + // chat = (chat as any).data + if (!chat) { + return throwError( + 'Could not found chat with id of ' + id + '!' + ); + } + + return of(chat); + }) + ); + } + + /** + * Update chat + * + * @param id + * @param chat + */ + updateChat(id: string, chat: AssistantChat): Observable { + return this.chats$.pipe( + take(1), + switchMap((chats) => + this._httpClient + .patch('api/apps/chat/chat', { + id, + chat, + }) + .pipe( + map((updatedChat) => { + // Find the index of the updated chat + const index = chats.findIndex( + (item) => item.id === id + ); + + // Update the chat + chats[index] = updatedChat; + + // Update the chats + this._chats.next(chats); + + // Return the updated contact + return updatedChat; + }), + switchMap((updatedChat) => + this.chat$.pipe( + take(1), + filter((item) => item && item.id === id), + tap(() => { + // Update the chat if it's selected + this._chat.next(updatedChat); + + // Return the updated chat + return updatedChat; + }) + ) + ) + ) + ) + ); + } + + /** + * Update chat + * + * @param id + * @param chat + */ + updateChat2(id: string, chat: AssistantChat): Observable { + return this.chats$.pipe( + take(1), + switchMap((chats) => + this._httpClient + .patch('api/apps/chat/chat', { + id, + chat, + }) + .pipe( + map((updatedChat) => { + // Find the index of the updated chat + const index = chats.findIndex( + (item) => item.id === id + ); + + // Update the chat + chats[index] = updatedChat; + + // Update the chats + this._chats.next(chats); + + // Update the chat if it's selected + this._chat.next(updatedChat); + + // Return the updated chat + return updatedChat; + }) + ) + ) + ); + } + + /** + * Reset the selected chat + */ + resetChat(): void { + this._chat.next({ id: '', messages: [], title: '' }); + } + + + /** + * Send a message + * + * @param chatId + * @param message + * @param llmId LLM identifier + */ + sendMessage(chatId: string, message: string, llmId: string): Observable { + return this.chats$.pipe( + take(1), + switchMap((chats) => + this._httpClient + .post(`api/chat/${chatId}/send`, { text: message, llmId }) + .pipe( + map((data: any) => { + const llmMessage = data.data; + + const newMessages = [ + { + value: message, + isMine: true, + }, + { + value: llmMessage, + isMine: false, + }, + ] + // // Find the index of the updated chat + const index = chats.findIndex( + (item) => item.id === chatId + ); + // + // // Update the chat + const chat = chats[index]; + chat.messages.push(...newMessages); + // // Update the chats + this._chats.next(chats); + // + // // Update the chat if it's selected + this._chat.next(chat); + // + // // Return the updated chat + return chat; + }) + ) + ) + ); + } +} diff --git a/frontend/src/app/modules/assistants/chats/assistant-list.component.html b/frontend/src/app/modules/assistants/chats/assistant-list.component.html new file mode 100644 index 00000000..92237ce8 --- /dev/null +++ b/frontend/src/app/modules/assistants/chats/assistant-list.component.html @@ -0,0 +1,160 @@ +
+ + + + + + +
+ +
+ +
+ +
+ +
+ + + + +
+
+ + +
+ @if (filteredChats.length > 0) { + @for ( + chat of filteredChats; + track trackByFn($index, chat) + ) { + +
+
+ {{ chat.title }} +
+
+ {{ chat.lastMessage }} +
+
+
+
+ {{ chat.lastMessageAt }} +
+ @if (hoveredAssistantId === chat.id) { + + } +
+
+ } + } @else { +
+ +
+ No chats +
+
+ } +
+
+ + + + @if (assistant !== null && assistant !== undefined) { +
+ +
+ } +
+
+
diff --git a/frontend/src/app/modules/assistants/chats/assistant-list.component.ts b/frontend/src/app/modules/assistants/chats/assistant-list.component.ts new file mode 100644 index 00000000..b644d036 --- /dev/null +++ b/frontend/src/app/modules/assistants/chats/assistant-list.component.ts @@ -0,0 +1,125 @@ +import { NgClass } from '@angular/common'; +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + OnDestroy, + OnInit, + ViewEncapsulation, +} from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatSidenavModule } from '@angular/material/sidenav'; +import { RouterLink, RouterOutlet } from '@angular/router'; +import { AssistantsService } from 'app/modules/assistants/assistants.service'; +import { AssistantChat } from 'app/modules/assistants/assistant.types'; +import { Subject, takeUntil } from 'rxjs'; + +@Component({ + selector: 'chat-chats', + templateUrl: './assistant-list.component.html', + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [ + MatSidenavModule, + MatButtonModule, + MatIconModule, + MatMenuModule, + MatFormFieldModule, + MatInputModule, + NgClass, + RouterLink, + RouterOutlet, + ], +}) +export class AssistantListComponent implements OnInit, OnDestroy { + assistant: AssistantChat[]; + filteredChats: AssistantChat[]; + selectedAssistant: AssistantChat; + hoveredAssistantId: string | null = null; + private _unsubscribeAll: Subject = new Subject(); + + /** + * Constructor + */ + constructor( + private _assistantService: AssistantsService, + private _changeDetectorRef: ChangeDetectorRef, + ) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Chats + this._assistantService.chats$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((chats: AssistantChat[]) => { + this.assistant = this.filteredChats = chats; + + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + + // Selected chat + this._assistantService.chat$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((chat: AssistantChat) => { + this.selectedAssistant = chat; + + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + + // Reset the chat + this._assistantService.resetChat(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Filter the chats + * + * @param query + */ + filterChats(query: string): void { + // Reset the filter + if (!query) { + this.filteredChats = this.assistant; + return; + } + + this.filteredChats = this.assistant.filter((chat) => + chat.title.toLowerCase().includes(query.toLowerCase()) + ); + } + + /** + * Track by function for ngFor loops + * + * @param index + * @param item + */ + trackByFn(index: number, item: any): any { + return item.id || index; + } +} diff --git a/frontend/src/app/modules/assistants/empty-assistant/empty-assistant.component.html b/frontend/src/app/modules/assistants/empty-assistant/empty-assistant.component.html new file mode 100644 index 00000000..2e1591d4 --- /dev/null +++ b/frontend/src/app/modules/assistants/empty-assistant/empty-assistant.component.html @@ -0,0 +1,16 @@ +
+ +
+ +
+ Select a conversation or start a new chat +
+
+
diff --git a/frontend/src/app/modules/assistants/empty-assistant/empty-assistant.component.ts b/frontend/src/app/modules/assistants/empty-assistant/empty-assistant.component.ts new file mode 100644 index 00000000..ff178803 --- /dev/null +++ b/frontend/src/app/modules/assistants/empty-assistant/empty-assistant.component.ts @@ -0,0 +1,21 @@ +import { + ChangeDetectionStrategy, + Component, + ViewEncapsulation, +} from '@angular/core'; +import { MatIconModule } from '@angular/material/icon'; + +@Component({ + selector: 'chat-empty-conversation', + templateUrl: './empty-assistant.component.html', + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [MatIconModule], +}) +export class EmptyAssistantComponent { + /** + * Constructor + */ + constructor() {} +} diff --git a/frontend/src/app/modules/auth/confirmation-required/confirmation-required.component.html b/frontend/src/app/modules/auth/confirmation-required/confirmation-required.component.html new file mode 100644 index 00000000..5962fb56 --- /dev/null +++ b/frontend/src/app/modules/auth/confirmation-required/confirmation-required.component.html @@ -0,0 +1,96 @@ +
+
+
+ +
+ +
+ + +
+ Confirmation required +
+
+ A confirmation mail with instructions has been sent to your + email address. Follow those instructions to confirm your email + address and activate your account. +
+ + +
+ Return to + sign in + +
+
+
+ +
diff --git a/frontend/src/app/modules/auth/confirmation-required/confirmation-required.component.ts b/frontend/src/app/modules/auth/confirmation-required/confirmation-required.component.ts new file mode 100644 index 00000000..81619612 --- /dev/null +++ b/frontend/src/app/modules/auth/confirmation-required/confirmation-required.component.ts @@ -0,0 +1,18 @@ +import { Component, ViewEncapsulation } from '@angular/core'; +import { RouterLink } from '@angular/router'; +import { fuseAnimations } from '@fuse/animations'; + +@Component({ + selector: 'auth-confirmation-required', + templateUrl: './confirmation-required.component.html', + encapsulation: ViewEncapsulation.None, + animations: fuseAnimations, + standalone: true, + imports: [RouterLink], +}) +export class AuthConfirmationRequiredComponent { + /** + * Constructor + */ + constructor() {} +} diff --git a/frontend/src/app/modules/auth/confirmation-required/confirmation-required.routes.ts b/frontend/src/app/modules/auth/confirmation-required/confirmation-required.routes.ts new file mode 100644 index 00000000..c2ac4413 --- /dev/null +++ b/frontend/src/app/modules/auth/confirmation-required/confirmation-required.routes.ts @@ -0,0 +1,9 @@ +import { Routes } from '@angular/router'; +import { AuthConfirmationRequiredComponent } from 'app/modules/auth/confirmation-required/confirmation-required.component'; + +export default [ + { + path: '', + component: AuthConfirmationRequiredComponent, + }, +] as Routes; diff --git a/frontend/src/app/modules/auth/forgot-password/forgot-password.component.html b/frontend/src/app/modules/auth/forgot-password/forgot-password.component.html new file mode 100644 index 00000000..6844851a --- /dev/null +++ b/frontend/src/app/modules/auth/forgot-password/forgot-password.component.html @@ -0,0 +1,147 @@ +
+
+
+ +
+ +
+ + +
+ Forgot password? +
+
+ Fill the form to reset your password +
+ + + @if (showAlert) { + + {{ alert.message }} + + } + + +
+ + + Email address + + @if (forgotPasswordForm.get('email').hasError('required')) { + Email address is required + } + @if (forgotPasswordForm.get('email').hasError('email')) { + + Please enter a valid email address + + } + + + + + + +
+ Return to + sign in + +
+
+
+
+ +
diff --git a/frontend/src/app/modules/auth/forgot-password/forgot-password.component.ts b/frontend/src/app/modules/auth/forgot-password/forgot-password.component.ts new file mode 100644 index 00000000..f6ad09b3 --- /dev/null +++ b/frontend/src/app/modules/auth/forgot-password/forgot-password.component.ts @@ -0,0 +1,122 @@ +import { Component, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; +import { + FormsModule, + NgForm, + ReactiveFormsModule, + UntypedFormBuilder, + UntypedFormGroup, + Validators, +} from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { RouterLink } from '@angular/router'; +import { fuseAnimations } from '@fuse/animations'; +import { FuseAlertComponent, FuseAlertType } from '@fuse/components/alert'; +import { AuthService } from 'app/core/auth/auth.service'; +import { finalize } from 'rxjs'; + +@Component({ + selector: 'auth-forgot-password', + templateUrl: './forgot-password.component.html', + encapsulation: ViewEncapsulation.None, + animations: fuseAnimations, + standalone: true, + imports: [ + FuseAlertComponent, + FormsModule, + ReactiveFormsModule, + MatFormFieldModule, + MatInputModule, + MatButtonModule, + MatProgressSpinnerModule, + RouterLink, + ], +}) +export class AuthForgotPasswordComponent implements OnInit { + @ViewChild('forgotPasswordNgForm') forgotPasswordNgForm: NgForm; + + alert: { type: FuseAlertType; message: string } = { + type: 'success', + message: '', + }; + forgotPasswordForm: UntypedFormGroup; + showAlert: boolean = false; + + /** + * Constructor + */ + constructor( + private _authService: AuthService, + private _formBuilder: UntypedFormBuilder + ) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Create the form + this.forgotPasswordForm = this._formBuilder.group({ + email: ['', [Validators.required, Validators.email]], + }); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Send the reset link + */ + sendResetLink(): void { + // Return if the form is invalid + if (this.forgotPasswordForm.invalid) { + return; + } + + // Disable the form + this.forgotPasswordForm.disable(); + + // Hide the alert + this.showAlert = false; + + // Forgot password + this._authService + .forgotPassword(this.forgotPasswordForm.get('email').value) + .pipe( + finalize(() => { + // Re-enable the form + this.forgotPasswordForm.enable(); + + // Reset the form + this.forgotPasswordNgForm.resetForm(); + + // Show the alert + this.showAlert = true; + }) + ) + .subscribe( + (response) => { + // Set the alert + this.alert = { + type: 'success', + message: + "Password reset sent! You'll receive an email if you are registered on our system.", + }; + }, + (response) => { + // Set the alert + this.alert = { + type: 'error', + message: + 'Email does not found! Are you sure you are already a member?', + }; + } + ); + } +} diff --git a/frontend/src/app/modules/auth/forgot-password/forgot-password.routes.ts b/frontend/src/app/modules/auth/forgot-password/forgot-password.routes.ts new file mode 100644 index 00000000..583dbb9b --- /dev/null +++ b/frontend/src/app/modules/auth/forgot-password/forgot-password.routes.ts @@ -0,0 +1,9 @@ +import { Routes } from '@angular/router'; +import { AuthForgotPasswordComponent } from 'app/modules/auth/forgot-password/forgot-password.component'; + +export default [ + { + path: '', + component: AuthForgotPasswordComponent, + }, +] as Routes; diff --git a/frontend/src/app/modules/auth/reset-password/reset-password.component.html b/frontend/src/app/modules/auth/reset-password/reset-password.component.html new file mode 100644 index 00000000..b44d63dd --- /dev/null +++ b/frontend/src/app/modules/auth/reset-password/reset-password.component.html @@ -0,0 +1,220 @@ +
+
+
+ +
+ +
+ + +
+ Reset your password +
+
+ Create a new password for your account +
+ + + @if (showAlert) { + + {{ alert.message }} + + } + + +
+ + + Password + + + Password is required + + + + + Password (Confirm) + + + @if ( + resetPasswordForm + .get('passwordConfirm') + .hasError('required') + ) { + + Password confirmation is required + + } + @if ( + resetPasswordForm + .get('passwordConfirm') + .hasError('mustMatch') + ) { + Passwords must match + } + + + + + + +
+ Return to + sign in + +
+
+
+
+ +
diff --git a/frontend/src/app/modules/auth/reset-password/reset-password.component.ts b/frontend/src/app/modules/auth/reset-password/reset-password.component.ts new file mode 100644 index 00000000..4d0966f9 --- /dev/null +++ b/frontend/src/app/modules/auth/reset-password/reset-password.component.ts @@ -0,0 +1,132 @@ +import { Component, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; +import { + FormsModule, + NgForm, + ReactiveFormsModule, + UntypedFormBuilder, + UntypedFormGroup, + Validators, +} from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { RouterLink } from '@angular/router'; +import { fuseAnimations } from '@fuse/animations'; +import { FuseAlertComponent, FuseAlertType } from '@fuse/components/alert'; +import { FuseValidators } from '@fuse/validators'; +import { AuthService } from 'app/core/auth/auth.service'; +import { finalize } from 'rxjs'; + +@Component({ + selector: 'auth-reset-password', + templateUrl: './reset-password.component.html', + encapsulation: ViewEncapsulation.None, + animations: fuseAnimations, + standalone: true, + imports: [ + FuseAlertComponent, + FormsModule, + ReactiveFormsModule, + MatFormFieldModule, + MatInputModule, + MatButtonModule, + MatIconModule, + MatProgressSpinnerModule, + RouterLink, + ], +}) +export class AuthResetPasswordComponent implements OnInit { + @ViewChild('resetPasswordNgForm') resetPasswordNgForm: NgForm; + + alert: { type: FuseAlertType; message: string } = { + type: 'success', + message: '', + }; + resetPasswordForm: UntypedFormGroup; + showAlert: boolean = false; + + /** + * Constructor + */ + constructor( + private _authService: AuthService, + private _formBuilder: UntypedFormBuilder + ) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Create the form + this.resetPasswordForm = this._formBuilder.group( + { + password: ['', Validators.required], + passwordConfirm: ['', Validators.required], + }, + { + validators: FuseValidators.mustMatch( + 'password', + 'passwordConfirm' + ), + } + ); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Reset password + */ + resetPassword(): void { + // Return if the form is invalid + if (this.resetPasswordForm.invalid) { + return; + } + + // Disable the form + this.resetPasswordForm.disable(); + + // Hide the alert + this.showAlert = false; + + // Send the request to the server + this._authService + .resetPassword(this.resetPasswordForm.get('password').value) + .pipe( + finalize(() => { + // Re-enable the form + this.resetPasswordForm.enable(); + + // Reset the form + this.resetPasswordNgForm.resetForm(); + + // Show the alert + this.showAlert = true; + }) + ) + .subscribe( + (response) => { + // Set the alert + this.alert = { + type: 'success', + message: 'Your password has been reset.', + }; + }, + (response) => { + // Set the alert + this.alert = { + type: 'error', + message: 'Something went wrong, please try again.', + }; + } + ); + } +} diff --git a/frontend/src/app/modules/auth/reset-password/reset-password.routes.ts b/frontend/src/app/modules/auth/reset-password/reset-password.routes.ts new file mode 100644 index 00000000..477481ee --- /dev/null +++ b/frontend/src/app/modules/auth/reset-password/reset-password.routes.ts @@ -0,0 +1,9 @@ +import { Routes } from '@angular/router'; +import { AuthResetPasswordComponent } from 'app/modules/auth/reset-password/reset-password.component'; + +export default [ + { + path: '', + component: AuthResetPasswordComponent, + }, +] as Routes; diff --git a/frontend/src/app/modules/auth/sign-in/sign-in.component.html b/frontend/src/app/modules/auth/sign-in/sign-in.component.html new file mode 100644 index 00000000..40e772da --- /dev/null +++ b/frontend/src/app/modules/auth/sign-in/sign-in.component.html @@ -0,0 +1,232 @@ +
+
+
+ +
+ +
+ + +
+ Sign in +
+
+
Don't have an account?
+ Sign up + +
+ + + + You are browsing Fuse Demo. Click on the "Sign + in" button to access the Demo and Documentation. + + + + @if (showAlert) { + + {{ alert.message }} + + } + + +
+ + + Email address + + @if (signInForm.get('email').hasError('required')) { + Email address is required + } + @if (signInForm.get('email').hasError('email')) { + + Please enter a valid email address + + } + + + + + Password + + + Password is required + + + +
+ + Remember me + + Forgot password? + +
+ + + + + +
+
+
Or continue with
+
+
+ + +
+ + + +
+
+
+
+ +
diff --git a/frontend/src/app/modules/auth/sign-in/sign-in.component.ts b/frontend/src/app/modules/auth/sign-in/sign-in.component.ts new file mode 100644 index 00000000..fd939178 --- /dev/null +++ b/frontend/src/app/modules/auth/sign-in/sign-in.component.ts @@ -0,0 +1,131 @@ +import { Component, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; +import { + FormsModule, + NgForm, + ReactiveFormsModule, + UntypedFormBuilder, + UntypedFormGroup, + Validators, +} from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { ActivatedRoute, Router, RouterLink } from '@angular/router'; +import { fuseAnimations } from '@fuse/animations'; +import { FuseAlertComponent, FuseAlertType } from '@fuse/components/alert'; +import { AuthService } from 'app/core/auth/auth.service'; + +@Component({ + selector: 'auth-sign-in', + templateUrl: './sign-in.component.html', + encapsulation: ViewEncapsulation.None, + animations: fuseAnimations, + standalone: true, + imports: [ + RouterLink, + FuseAlertComponent, + FormsModule, + ReactiveFormsModule, + MatFormFieldModule, + MatInputModule, + MatButtonModule, + MatIconModule, + MatCheckboxModule, + MatProgressSpinnerModule, + ], +}) +export class AuthSignInComponent implements OnInit { + @ViewChild('signInNgForm') signInNgForm: NgForm; + + alert: { type: FuseAlertType; message: string } = { + type: 'success', + message: '', + }; + signInForm: UntypedFormGroup; + showAlert: boolean = false; + + /** + * Constructor + */ + constructor( + private _activatedRoute: ActivatedRoute, + private _authService: AuthService, + private _formBuilder: UntypedFormBuilder, + private _router: Router + ) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Create the form + this.signInForm = this._formBuilder.group({ + email: [ + 'hughes.brian@company.com', + [Validators.required, Validators.email], + ], + password: ['admin', Validators.required], + rememberMe: [''], + }); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Sign in + */ + signIn(): void { + // Return if the form is invalid + if (this.signInForm.invalid) { + return; + } + + // Disable the form + this.signInForm.disable(); + + // Hide the alert + this.showAlert = false; + + // Sign in + this._authService.signIn(this.signInForm.value).subscribe( + () => { + // Set the redirect url. + // The '/signed-in-redirect' is a dummy url to catch the request and redirect the user + // to the correct page after a successful sign in. This way, that url can be set via + // routing file and we don't have to touch here. + const redirectURL = + this._activatedRoute.snapshot.queryParamMap.get( + 'redirectURL' + ) || '/signed-in-redirect'; + + // Navigate to the redirect url + this._router.navigateByUrl(redirectURL); + }, + (response) => { + // Re-enable the form + this.signInForm.enable(); + + // Reset the form + this.signInNgForm.resetForm(); + + // Set the alert + this.alert = { + type: 'error', + message: 'Wrong email or password', + }; + + // Show the alert + this.showAlert = true; + } + ); + } +} diff --git a/frontend/src/app/modules/auth/sign-in/sign-in.routes.ts b/frontend/src/app/modules/auth/sign-in/sign-in.routes.ts new file mode 100644 index 00000000..d3313ae8 --- /dev/null +++ b/frontend/src/app/modules/auth/sign-in/sign-in.routes.ts @@ -0,0 +1,9 @@ +import { Routes } from '@angular/router'; +import { AuthSignInComponent } from 'app/modules/auth/sign-in/sign-in.component'; + +export default [ + { + path: '', + component: AuthSignInComponent, + }, +] as Routes; diff --git a/frontend/src/app/modules/auth/sign-out/sign-out.component.html b/frontend/src/app/modules/auth/sign-out/sign-out.component.html new file mode 100644 index 00000000..55fb1757 --- /dev/null +++ b/frontend/src/app/modules/auth/sign-out/sign-out.component.html @@ -0,0 +1,41 @@ +
+
+
+ +
+ +
+ + +
+ You have signed out! +
+
+ + @if (countdown > 0) { + Redirecting in + {{ countdown | i18nPlural: countdownMapping }} + } + + + @if (countdown === 0) { + You are now being redirected! + } +
+ + +
+ Go to + sign in + +
+
+
+
diff --git a/frontend/src/app/modules/auth/sign-out/sign-out.component.ts b/frontend/src/app/modules/auth/sign-out/sign-out.component.ts new file mode 100644 index 00000000..e465d3e9 --- /dev/null +++ b/frontend/src/app/modules/auth/sign-out/sign-out.component.ts @@ -0,0 +1,62 @@ +import { I18nPluralPipe } from '@angular/common'; +import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; +import { Router, RouterLink } from '@angular/router'; +import { AuthService } from 'app/core/auth/auth.service'; +import { Subject, finalize, takeUntil, takeWhile, tap, timer } from 'rxjs'; + +@Component({ + selector: 'auth-sign-out', + templateUrl: './sign-out.component.html', + encapsulation: ViewEncapsulation.None, + standalone: true, + imports: [RouterLink, I18nPluralPipe], +}) +export class AuthSignOutComponent implements OnInit, OnDestroy { + countdown: number = 5; + countdownMapping: any = { + '=1': '# second', + other: '# seconds', + }; + private _unsubscribeAll: Subject = new Subject(); + + /** + * Constructor + */ + constructor( + private _authService: AuthService, + private _router: Router + ) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Sign out + this._authService.signOut(); + + // Redirect after the countdown + timer(1000, 1000) + .pipe( + finalize(() => { + this._router.navigate(['sign-in']); + }), + takeWhile(() => this.countdown > 0), + takeUntil(this._unsubscribeAll), + tap(() => this.countdown--) + ) + .subscribe(); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } +} diff --git a/frontend/src/app/modules/auth/sign-out/sign-out.routes.ts b/frontend/src/app/modules/auth/sign-out/sign-out.routes.ts new file mode 100644 index 00000000..1e0cb146 --- /dev/null +++ b/frontend/src/app/modules/auth/sign-out/sign-out.routes.ts @@ -0,0 +1,9 @@ +import { Routes } from '@angular/router'; +import { AuthSignOutComponent } from 'app/modules/auth/sign-out/sign-out.component'; + +export default [ + { + path: '', + component: AuthSignOutComponent, + }, +] as Routes; diff --git a/frontend/src/app/modules/auth/sign-up/sign-up.component.html b/frontend/src/app/modules/auth/sign-up/sign-up.component.html new file mode 100644 index 00000000..bae1c5f1 --- /dev/null +++ b/frontend/src/app/modules/auth/sign-up/sign-up.component.html @@ -0,0 +1,215 @@ +
+
+
+ +
+ +
+ + +
+ Sign up +
+
+
Already have an account?
+ Sign in + +
+ + + @if (showAlert) { + + {{ alert.message }} + + } + + +
+ + + Full name + + @if (signUpForm.get('name').hasError('required')) { + Full name is required + } + + + + + Email address + + @if (signUpForm.get('email').hasError('required')) { + Email address is required + } + @if (signUpForm.get('email').hasError('email')) { + + Please enter a valid email address + + } + + + + + Password + + + Password is required + + + + + Company + + + + +
+ + I agree with + Terms + + and + Privacy Policy + + +
+ + + +
+
+
+ +
diff --git a/frontend/src/app/modules/auth/sign-up/sign-up.component.ts b/frontend/src/app/modules/auth/sign-up/sign-up.component.ts new file mode 100644 index 00000000..e2375581 --- /dev/null +++ b/frontend/src/app/modules/auth/sign-up/sign-up.component.ts @@ -0,0 +1,120 @@ +import { Component, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; +import { + FormsModule, + NgForm, + ReactiveFormsModule, + UntypedFormBuilder, + UntypedFormGroup, + Validators, +} from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { Router, RouterLink } from '@angular/router'; +import { fuseAnimations } from '@fuse/animations'; +import { FuseAlertComponent, FuseAlertType } from '@fuse/components/alert'; +import { AuthService } from 'app/core/auth/auth.service'; + +@Component({ + selector: 'auth-sign-up', + templateUrl: './sign-up.component.html', + encapsulation: ViewEncapsulation.None, + animations: fuseAnimations, + standalone: true, + imports: [ + RouterLink, + FuseAlertComponent, + FormsModule, + ReactiveFormsModule, + MatFormFieldModule, + MatInputModule, + MatButtonModule, + MatIconModule, + MatCheckboxModule, + MatProgressSpinnerModule, + ], +}) +export class AuthSignUpComponent implements OnInit { + @ViewChild('signUpNgForm') signUpNgForm: NgForm; + + alert: { type: FuseAlertType; message: string } = { + type: 'success', + message: '', + }; + signUpForm: UntypedFormGroup; + showAlert: boolean = false; + + /** + * Constructor + */ + constructor( + private _authService: AuthService, + private _formBuilder: UntypedFormBuilder, + private _router: Router + ) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Create the form + this.signUpForm = this._formBuilder.group({ + name: ['', Validators.required], + email: ['', [Validators.required, Validators.email]], + password: ['', Validators.required], + company: [''], + agreements: ['', Validators.requiredTrue], + }); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Sign up + */ + signUp(): void { + // Do nothing if the form is invalid + if (this.signUpForm.invalid) { + return; + } + + // Disable the form + this.signUpForm.disable(); + + // Hide the alert + this.showAlert = false; + + // Sign up + this._authService.signUp(this.signUpForm.value).subscribe( + (response) => { + // Navigate to the confirmation required page + this._router.navigateByUrl('/confirmation-required'); + }, + (response) => { + // Re-enable the form + this.signUpForm.enable(); + + // Reset the form + this.signUpNgForm.resetForm(); + + // Set the alert + this.alert = { + type: 'error', + message: 'Something went wrong, please try again.', + }; + + // Show the alert + this.showAlert = true; + } + ); + } +} diff --git a/frontend/src/app/modules/auth/sign-up/sign-up.routes.ts b/frontend/src/app/modules/auth/sign-up/sign-up.routes.ts new file mode 100644 index 00000000..19d2728e --- /dev/null +++ b/frontend/src/app/modules/auth/sign-up/sign-up.routes.ts @@ -0,0 +1,9 @@ +import { Routes } from '@angular/router'; +import { AuthSignUpComponent } from 'app/modules/auth/sign-up/sign-up.component'; + +export default [ + { + path: '', + component: AuthSignUpComponent, + }, +] as Routes; diff --git a/frontend/src/app/modules/auth/unlock-session/unlock-session.component.html b/frontend/src/app/modules/auth/unlock-session/unlock-session.component.html new file mode 100644 index 00000000..cbd6c5dd --- /dev/null +++ b/frontend/src/app/modules/auth/unlock-session/unlock-session.component.html @@ -0,0 +1,175 @@ +
+
+
+ +
+ +
+ + +
+ Unlock your session +
+
+ Your session is locked due to inactivity +
+ + + @if (showAlert) { + + {{ alert.message }} + + } + + +
+ + + Full name + + + + + + Password + + + Password is required + + + + + + +
+ I'm not + {{ name }} +
+
+
+
+ +
diff --git a/frontend/src/app/modules/auth/unlock-session/unlock-session.component.ts b/frontend/src/app/modules/auth/unlock-session/unlock-session.component.ts new file mode 100644 index 00000000..08e06304 --- /dev/null +++ b/frontend/src/app/modules/auth/unlock-session/unlock-session.component.ts @@ -0,0 +1,149 @@ +import { Component, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; +import { + FormsModule, + NgForm, + ReactiveFormsModule, + UntypedFormBuilder, + UntypedFormGroup, + Validators, +} from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { ActivatedRoute, Router, RouterLink } from '@angular/router'; +import { fuseAnimations } from '@fuse/animations'; +import { FuseAlertComponent, FuseAlertType } from '@fuse/components/alert'; +import { AuthService } from 'app/core/auth/auth.service'; +import { UserService } from 'app/core/user/user.service'; + +@Component({ + selector: 'auth-unlock-session', + templateUrl: './unlock-session.component.html', + encapsulation: ViewEncapsulation.None, + animations: fuseAnimations, + standalone: true, + imports: [ + FuseAlertComponent, + FormsModule, + ReactiveFormsModule, + MatFormFieldModule, + MatInputModule, + MatButtonModule, + MatIconModule, + MatProgressSpinnerModule, + RouterLink, + ], +}) +export class AuthUnlockSessionComponent implements OnInit { + @ViewChild('unlockSessionNgForm') unlockSessionNgForm: NgForm; + + alert: { type: FuseAlertType; message: string } = { + type: 'success', + message: '', + }; + name: string; + showAlert: boolean = false; + unlockSessionForm: UntypedFormGroup; + private _email: string; + + /** + * Constructor + */ + constructor( + private _activatedRoute: ActivatedRoute, + private _authService: AuthService, + private _formBuilder: UntypedFormBuilder, + private _router: Router, + private _userService: UserService + ) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Get the user's name + this._userService.user$.subscribe((user) => { + this.name = user.name; + this._email = user.email; + }); + + // Create the form + this.unlockSessionForm = this._formBuilder.group({ + name: [ + { + value: this.name, + disabled: true, + }, + ], + password: ['', Validators.required], + }); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Unlock + */ + unlock(): void { + // Return if the form is invalid + if (this.unlockSessionForm.invalid) { + return; + } + + // Disable the form + this.unlockSessionForm.disable(); + + // Hide the alert + this.showAlert = false; + + this._authService + .unlockSession({ + email: this._email ?? '', + password: this.unlockSessionForm.get('password').value, + }) + .subscribe( + () => { + // Set the redirect url. + // The '/signed-in-redirect' is a dummy url to catch the request and redirect the user + // to the correct page after a successful sign in. This way, that url can be set via + // routing file and we don't have to touch here. + const redirectURL = + this._activatedRoute.snapshot.queryParamMap.get( + 'redirectURL' + ) || '/signed-in-redirect'; + + // Navigate to the redirect url + this._router.navigateByUrl(redirectURL); + }, + (response) => { + // Re-enable the form + this.unlockSessionForm.enable(); + + // Reset the form + this.unlockSessionNgForm.resetForm({ + name: { + value: this.name, + disabled: true, + }, + }); + + // Set the alert + this.alert = { + type: 'error', + message: 'Invalid password', + }; + + // Show the alert + this.showAlert = true; + } + ); + } +} diff --git a/frontend/src/app/modules/auth/unlock-session/unlock-session.routes.ts b/frontend/src/app/modules/auth/unlock-session/unlock-session.routes.ts new file mode 100644 index 00000000..a8573940 --- /dev/null +++ b/frontend/src/app/modules/auth/unlock-session/unlock-session.routes.ts @@ -0,0 +1,9 @@ +import { Routes } from '@angular/router'; +import { AuthUnlockSessionComponent } from 'app/modules/auth/unlock-session/unlock-session.component'; + +export default [ + { + path: '', + component: AuthUnlockSessionComponent, + }, +] as Routes; diff --git a/frontend/src/app/modules/code-review/code-review.component.html b/frontend/src/app/modules/code-review/code-review.component.html new file mode 100644 index 00000000..0680b43f --- /dev/null +++ b/frontend/src/app/modules/code-review/code-review.component.html @@ -0,0 +1 @@ + diff --git a/frontend/src/app/modules/code-review/code-review.component.ts b/frontend/src/app/modules/code-review/code-review.component.ts new file mode 100644 index 00000000..b3607f6a --- /dev/null +++ b/frontend/src/app/modules/code-review/code-review.component.ts @@ -0,0 +1,21 @@ +import { + ChangeDetectionStrategy, + Component, + ViewEncapsulation, +} from '@angular/core'; +import { RouterOutlet } from '@angular/router'; + +@Component({ + selector: 'code-reviews', + templateUrl: './code-review.component.html', + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [RouterOutlet], +}) +export class CodeReviewComponent { + /** + * Constructor + */ + constructor() {} +} diff --git a/frontend/src/app/code-review/code-review.model.ts b/frontend/src/app/modules/code-review/code-review.model.ts similarity index 100% rename from frontend/src/app/code-review/code-review.model.ts rename to frontend/src/app/modules/code-review/code-review.model.ts diff --git a/frontend/src/app/modules/code-review/code-review.routes.ts b/frontend/src/app/modules/code-review/code-review.routes.ts new file mode 100644 index 00000000..2ad63ac9 --- /dev/null +++ b/frontend/src/app/modules/code-review/code-review.routes.ts @@ -0,0 +1,20 @@ +import { Routes } from '@angular/router'; +import { inject } from '@angular/core'; +import {CodeReviewEditComponent} from "./edit/code-review-edit.component"; +import {CodeReviewListComponent} from "./list/code-review-list.component"; + +export default [ + { + path: '', + component: CodeReviewListComponent, + // data: { title: marker('Code Reviews') }, + }, + { + path: 'new', + component: CodeReviewEditComponent, + }, + { + path: 'edit/:id', + component: CodeReviewEditComponent, + }, +] as Routes; diff --git a/frontend/src/app/code-review/code-review.service.ts b/frontend/src/app/modules/code-review/code-review.service.ts similarity index 82% rename from frontend/src/app/code-review/code-review.service.ts rename to frontend/src/app/modules/code-review/code-review.service.ts index bd77b24a..e0d3a227 100644 --- a/frontend/src/app/code-review/code-review.service.ts +++ b/frontend/src/app/modules/code-review/code-review.service.ts @@ -2,13 +2,16 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { CodeReviewConfig } from './code-review.model'; -import { Data } from '@shared'; + +interface Data { + data: T +} @Injectable({ providedIn: 'root', }) export class CodeReviewService { - private apiUrl = '/code-review-configs'; + private apiUrl = 'api/code-review-configs'; constructor(private http: HttpClient) {} @@ -31,4 +34,8 @@ export class CodeReviewService { deleteCodeReviewConfig(id: string): Observable { return this.http.delete(`${this.apiUrl}/${id}`); } + + deleteCodeReviewConfigs(ids: string[]): Observable { + return this.http.post(`${this.apiUrl}/bulk-delete`, { ids }); + } } diff --git a/frontend/src/app/modules/code-review/edit/code-review-edit.component.html b/frontend/src/app/modules/code-review/edit/code-review-edit.component.html new file mode 100644 index 00000000..57d390cd --- /dev/null +++ b/frontend/src/app/modules/code-review/edit/code-review-edit.component.html @@ -0,0 +1,142 @@ +
+ +
+
+
+

+ {{ configId ? 'Edit' : 'Create' }} Code Review Configuration +

+
+
+
+ + +
+
+
+ + Description + + + +
+
+ + Included File Extensions + + + {{ ext }} + cancel + + + + +
+ +
+ + Required Text In Diff + + + {{ text }} + cancel + + + + +
+
+
+ +
+
+ + Tags + + + {{ tag }} + cancel + + + + +
+ +
+ + Project Paths + + + {{ path }} + cancel + + + + +
+ +
+
+ +
+
+

+ Examples + +

+
+
+ + Code + + + + Review Comment + + + +
+
+ +
+ + +
+
+
+
+
diff --git a/frontend/src/app/code-review/code-review-edit.component.ts b/frontend/src/app/modules/code-review/edit/code-review-edit.component.ts similarity index 87% rename from frontend/src/app/code-review/code-review-edit.component.ts rename to frontend/src/app/modules/code-review/edit/code-review-edit.component.ts index 4ce96e22..4432cfc6 100644 --- a/frontend/src/app/code-review/code-review-edit.component.ts +++ b/frontend/src/app/modules/code-review/edit/code-review-edit.component.ts @@ -1,13 +1,38 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormGroup, Validators, FormArray, AbstractControl, ValidationErrors } from '@angular/forms'; +import { + FormBuilder, + FormGroup, + Validators, + FormArray, + AbstractControl, + ValidationErrors, + ReactiveFormsModule +} from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; -import { CodeReviewService } from './code-review.service'; -import { MatChipInputEvent } from '@angular/material/chips'; +import { CodeReviewService } from '../code-review.service'; +import {MatChipInputEvent, MatChipsModule} from '@angular/material/chips'; +import {CommonModule} from "@angular/common"; +import {MatSnackBarModule} from "@angular/material/snack-bar"; +import {MatButtonModule} from "@angular/material/button"; +import {MatFormFieldModule} from "@angular/material/form-field"; +import {MatIconModule} from "@angular/material/icon"; +import {MatInputModule} from "@angular/material/input"; @Component({ selector: 'app-code-review-edit', templateUrl: './code-review-edit.component.html', - styleUrls: ['./code-review-edit.component.scss'], + standalone: true, + imports: [ + CommonModule, + MatSnackBarModule, + ReactiveFormsModule, + MatButtonModule, + MatFormFieldModule, + MatChipsModule, + MatIconModule, + MatFormFieldModule, // Add this line + MatInputModule, // Add this line + ], }) export class CodeReviewEditComponent implements OnInit { editForm: FormGroup; @@ -26,9 +51,13 @@ export class CodeReviewEditComponent implements OnInit { ngOnInit() { this.configId = this.route.snapshot.paramMap.get('id'); + console.log(this.configId); if (this.configId) { this.loadConfigData(); + } else { + this.addExample(); } + this.editForm.valueChanges.subscribe(() => { console.log('Form validity:', this.editForm.valid); console.log('Form value:', this.editForm.value); diff --git a/frontend/src/app/modules/code-review/list/code-review-list.component.html b/frontend/src/app/modules/code-review/list/code-review-list.component.html new file mode 100644 index 00000000..7cca8a3f --- /dev/null +++ b/frontend/src/app/modules/code-review/list/code-review-list.component.html @@ -0,0 +1,82 @@ +
+ +
+ @if (isLoading) { +
+ +
+ } + +
Code review configurations
+ +
+ + + +
+
+ + + + + + + + + + + + + +
+ + + + Description + {{ config.description }} +
+ + +

{{ errorMessage }}

+

No code review configurations found.

+ +
+ diff --git a/frontend/src/app/modules/code-review/list/code-review-list.component.ts b/frontend/src/app/modules/code-review/list/code-review-list.component.ts new file mode 100644 index 00000000..1712b32e --- /dev/null +++ b/frontend/src/app/modules/code-review/list/code-review-list.component.ts @@ -0,0 +1,130 @@ +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { CodeReviewService } from '../code-review.service'; +import { CodeReviewConfig } from '../code-review.model'; +import { FuseConfirmationService } from '@fuse/services/confirmation'; +import { MatTableDataSource } from '@angular/material/table'; +import { SelectionModel } from '@angular/cdk/collections'; +import { MatSnackBar } from '@angular/material/snack-bar'; +import { MatButtonModule } from "@angular/material/button"; +import { MatIconModule } from "@angular/material/icon"; +import { MatCheckboxModule } from "@angular/material/checkbox"; +import { MatToolbarModule } from "@angular/material/toolbar"; +import { CommonModule } from '@angular/common'; +import { MatTableModule } from '@angular/material/table'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import {MatProgressBar} from "@angular/material/progress-bar"; + +@Component({ + selector: 'app-code-review-list', + templateUrl: './code-review-list.component.html', + standalone: true, + imports: [ + CommonModule, + MatButtonModule, + MatIconModule, + MatCheckboxModule, + MatToolbarModule, + MatTableModule, + MatProgressSpinnerModule, + MatProgressBar, + ] +}) +export class CodeReviewListComponent implements OnInit { + configs$: MatTableDataSource = new MatTableDataSource([]); + selection = new SelectionModel(true, []); + displayedColumns: string[] = ['select', 'description']; + isLoading = false; + errorMessage = ''; + + constructor( + private codeReviewService: CodeReviewService, + private router: Router, + private dialog: FuseConfirmationService, + private snackBar: MatSnackBar + ) {} + + ngOnInit() { + this.loadConfigs(); + } + + loadConfigs() { + this.isLoading = true; + this.codeReviewService.getCodeReviewConfigs().subscribe( + (configs) => { + this.configs$.data = configs.data; + this.isLoading = false; + this.selection.clear(); + }, + (error) => { + this.errorMessage = 'Error loading configurations'; + this.isLoading = false; + } + ); + } + + openEditPage(id?: string) { + if (id) { + this.router.navigate(['/code-reviews/edit', id]).catch(console.error); + } else { + this.router.navigate(['/code-reviews/new']).catch(console.error); + } + } + + isAllSelected(): boolean { + const numSelected = this.selection.selected.length; + const numRows = this.configs$.data.length; + return numSelected === numRows; + } + + masterToggle(): void { + this.isAllSelected() + ? this.selection.clear() + : this.configs$.data.forEach((row) => this.selection.select(row)); + } + + deleteSelectedConfigs(): void { + const selectedIds = this.selection.selected.map((config) => config.id); + if (selectedIds.length === 0) { + this.snackBar.open('No configurations selected for deletion', 'Close', { duration: 3000 }); + return; + } + + this.dialog + .open({ + title: 'Confirm Deletion', + message: `Are you sure you want to delete ${selectedIds.length} configuration(s)?`, + actions: { + confirm: { + show: true, + label: 'Delete', + color: 'warn' + }, + cancel: { + show: true, + label: 'Cancel' + } + } + }) + .afterClosed() + .subscribe((result) => { + if (result === 'confirmed') { + this.codeReviewService.deleteCodeReviewConfigs(selectedIds).subscribe( + () => { + this.snackBar.open('Configurations deleted successfully', 'Close', { duration: 3000 }); + this.loadConfigs(); + }, + (error) => { + this.errorMessage = 'Error deleting configurations'; + this.snackBar.open('Error deleting configurations', 'Close', { duration: 3000 }); + } + ); + } + }); + } + + refreshConfigs(): void { + this.loadConfigs(); + this.snackBar.open('Configurations refreshed', 'Close', { duration: 1000 }); + } +} diff --git a/frontend/src/app/modules/landing/home/home.component.html b/frontend/src/app/modules/landing/home/home.component.html new file mode 100644 index 00000000..b15371c1 --- /dev/null +++ b/frontend/src/app/modules/landing/home/home.component.html @@ -0,0 +1,36 @@ +
+
+
+ Logo image +

Landing Module

+

+ This can be the landing or the welcome page of your application. + If you have an SSR (Server Side Rendering) setup, or if you + don't need to have Search engine visibility and optimizations, + you can even use this page as your primary landing page. +

+

+ This is a separate "module", it has its own directory and + routing setup and also it's completely separated from the actual + application. This is also a simple example of a multiple + applications setup that uses the same codebase. You can have + different entry points and essentially have different + applications within the same codebase. +

+
+ +
+
diff --git a/frontend/src/app/modules/landing/home/home.component.ts b/frontend/src/app/modules/landing/home/home.component.ts new file mode 100644 index 00000000..ff291767 --- /dev/null +++ b/frontend/src/app/modules/landing/home/home.component.ts @@ -0,0 +1,18 @@ +import { Component, ViewEncapsulation } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { RouterLink } from '@angular/router'; + +@Component({ + selector: 'landing-home', + templateUrl: './home.component.html', + encapsulation: ViewEncapsulation.None, + standalone: true, + imports: [MatButtonModule, RouterLink, MatIconModule], +}) +export class LandingHomeComponent { + /** + * Constructor + */ + constructor() {} +} diff --git a/frontend/src/app/modules/landing/home/home.routes.ts b/frontend/src/app/modules/landing/home/home.routes.ts new file mode 100644 index 00000000..6758f550 --- /dev/null +++ b/frontend/src/app/modules/landing/home/home.routes.ts @@ -0,0 +1,9 @@ +import { Routes } from '@angular/router'; +import { LandingHomeComponent } from 'app/modules/landing/home/home.component'; + +export default [ + { + path: '', + component: LandingHomeComponent, + }, +] as Routes; diff --git a/frontend/src/app/modules/profile/account/account.component.html b/frontend/src/app/modules/profile/account/account.component.html new file mode 100644 index 00000000..97ad701e --- /dev/null +++ b/frontend/src/app/modules/profile/account/account.component.html @@ -0,0 +1,227 @@ +
+ +
+ + + + +
+
Profile
+
+ +
+ +
+ + Email + + +
+
+ + +
+
Default Human-in-the-Loop Settings
+
+
+ +
+ + Spend $USD + + +
+ +
+ + Control Loop Iterations + + +
+
+ + +
+ + +
+
LLM API Keys
+
+
+ +
+ + Anthropic + + +
+ +
+ + OpenAI + + +
+ +
+ + Groq + + +
+ +
+ + TogetherAI + + +
+ +
+ + Fireworks + + +
+ +
+ + DeepSeek + + +
+
+ + +
+ + +
+
Tool/Function Configurations
+
+
+ +
+
GitHub
+ + Token + + +
+ +
+
GitLab
+
+ +
+ + Domain + + +
+ +
+ + Token + + +
+ +
+ + Top Level Groups (comma separated) + + +
+
+
+ +
+
Jira
+
+ +
+ + Base URL + + +
+ +
+ + Email + + +
+ +
+ + Token + + +
+
+
+ +
+
Slack
+
+ +
+ + Token + + +
+ +
+ + User ID + + +
+ +
+ + Webhook URL + + +
+
+
+ +
+
Perplexity
+ + Key + + +
+
+ + +
+ + +
+ + +
+
+
diff --git a/frontend/src/app/modules/profile/account/account.component.ts b/frontend/src/app/modules/profile/account/account.component.ts new file mode 100644 index 00000000..ede23372 --- /dev/null +++ b/frontend/src/app/modules/profile/account/account.component.ts @@ -0,0 +1,136 @@ +import { TextFieldModule } from '@angular/cdk/text-field'; +import { + ChangeDetectionStrategy, + Component, + OnInit, + ViewEncapsulation, +} from '@angular/core'; +import { + FormGroup, + FormControl, + Validators, + ReactiveFormsModule, +} from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { HttpClient } from '@angular/common/http'; +import { MatSnackBar } from '@angular/material/snack-bar'; + +@Component({ + selector: 'settings-account', + templateUrl: './account.component.html', + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [ + MatFormFieldModule, + MatInputModule, + MatButtonModule, + ReactiveFormsModule, + ], +}) +export class SettingsAccountComponent implements OnInit { + accountForm: FormGroup; + + /** + * Constructor + */ + constructor( + private http: HttpClient, + private snackBar: MatSnackBar + ) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Create the form using new FormGroup and new FormControl + this.accountForm = new FormGroup({ + id: new FormControl({ value: '', disabled: true }), + username: new FormControl(''), + email: new FormControl('', [Validators.required, Validators.email]), + enabled: new FormControl(false), + hilBudget: new FormControl(0), + hilCount: new FormControl(0), + llmConfig: new FormGroup({ + anthropicKey: new FormControl(''), + openaiKey: new FormControl(''), + groqKey: new FormControl(''), + togetheraiKey: new FormControl(''), + fireworksKey: new FormControl(''), + deepseekKey: new FormControl(''), + }), + functionConfig: new FormGroup({ + GitHub: new FormGroup({ + token: new FormControl(''), + }), + GitLab: new FormGroup({ + host: new FormControl(''), + token: new FormControl(''), + topLevelGroups: new FormControl(''), + }), + Jira: new FormGroup({ + baseUrl: new FormControl(''), + email: new FormControl(''), + token: new FormControl(''), + }), + Slack: new FormGroup({ + token: new FormControl(''), + userId: new FormControl(''), + webhookUrl: new FormControl(''), + }), + Perplexity: new FormGroup({ + key: new FormControl(''), + }), + }), + }); + + // Load the user profile data + this.loadUserProfile(); + } + + // Load user profile data + private loadUserProfile(): void { + this.http.get('/api/profile/view').subscribe( + (response: any) => { + console.log('User profile data:', response.data); + this.accountForm.patchValue(response.data); + }, + (error) => { + this.snackBar.open('Failed to load user profile', 'Close', { duration: 3000 }); + console.error(error); + } + ); + } + + // Save user profile data + onSave(): void { + if (this.accountForm.invalid) { + // Handle invalid form state + return; + } + + const formData = this.accountForm.getRawValue(); + + this.http.post('/api/profile/update', { user: formData }).subscribe( + () => { + this.snackBar.open('Profile updated', 'Close', { duration: 3000 }); + }, + (error) => { + this.snackBar.open('Failed to save profile.', 'Close', { duration: 3000 }); + console.error(error); + } + ); + } + + // Optional: Implement a cancel method + onCancel(): void { + this.accountForm.reset(); + this.loadUserProfile(); + } +} diff --git a/frontend/src/app/modules/profile/profile.component.html b/frontend/src/app/modules/profile/profile.component.html new file mode 100644 index 00000000..a0ea9ea3 --- /dev/null +++ b/frontend/src/app/modules/profile/profile.component.html @@ -0,0 +1,114 @@ +
+ + + + +
+ +
+ Settings +
+ +
+ +
+
+ +
+ @for (panel of panels; track trackByFn($index, panel)) { +
+ +
+
+ {{ panel.title }} +
+
+ {{ panel.description }} +
+
+
+ } +
+
+ + + + +
+ +
+ + + + +
+ {{ getPanelInfo(selectedPanel).title }} +
+
+ + +
+ @switch (selectedPanel) { + + @case ('account') { + + } + + @case ('ui') { + + } + } +
+
+
+
+
diff --git a/frontend/src/app/modules/profile/profile.component.ts b/frontend/src/app/modules/profile/profile.component.ts new file mode 100644 index 00000000..fe4c57ac --- /dev/null +++ b/frontend/src/app/modules/profile/profile.component.ts @@ -0,0 +1,160 @@ +import { NgClass } from '@angular/common'; +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + OnDestroy, + OnInit, + ViewChild, + ViewEncapsulation, +} from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatDrawer, MatSidenavModule } from '@angular/material/sidenav'; +import { FuseMediaWatcherService } from '@fuse/services/media-watcher'; +import { Subject, takeUntil } from 'rxjs'; +import { SettingsAccountComponent } from './account/account.component'; +import { UiSettingsComponent } from './ui-settings/ui-settings.component'; + +@Component({ + selector: 'settings', + templateUrl: './profile.component.html', + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [ + MatSidenavModule, + MatButtonModule, + MatIconModule, + NgClass, + SettingsAccountComponent, + UiSettingsComponent, + ], +}) +export class ProfileComponent implements OnInit, OnDestroy { + @ViewChild('drawer') drawer: MatDrawer; + drawerMode: 'over' | 'side' = 'side'; + drawerOpened: boolean = true; + panels: any[] = []; + selectedPanel: string = 'account'; + private _unsubscribeAll: Subject = new Subject(); + + /** + * Constructor + */ + constructor( + private _changeDetectorRef: ChangeDetectorRef, + private _fuseMediaWatcherService: FuseMediaWatcherService + ) { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Setup available panels + this.panels = [ + { + id: 'account', + icon: 'heroicons_outline:user-circle', + title: 'Account', + description: + 'Manage your profile and LLM API keys', + }, + // { + // id: 'security', + // icon: 'heroicons_outline:lock-closed', + // title: 'Security', + // description: + // 'Manage your password and 2-step verification preferences', + // }, + // { + // id: 'plan-billing', + // icon: 'heroicons_outline:credit-card', + // title: 'Plan & Billing', + // description: + // 'Manage your subscription plan, payment method and billing information', + // }, + // { + // id: 'notifications', + // icon: 'heroicons_outline:bell', + // title: 'Notifications', + // description: "Manage when you'll be notified on which channels", + // }, + { + id: 'ui', + icon: 'heroicons_outline:user-group', + title: 'UI', + description: + 'Theme, layout and scheme settings', + }, + ]; + + // Subscribe to media changes + this._fuseMediaWatcherService.onMediaChange$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(({matchingAliases}) => { + // Set the drawerMode and drawerOpened + if (matchingAliases.includes('lg')) { + this.drawerMode = 'side'; + this.drawerOpened = true; + } else { + this.drawerMode = 'over'; + this.drawerOpened = false; + } + + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Navigate to the panel + * + * @param panel + */ + goToPanel(panel: string): void { + this.selectedPanel = panel; + + // Close the drawer on 'over' mode + if (this.drawerMode === 'over') { + this.drawer.close(); + } + } + + /** + * Get the details of the panel + * + * @param id + */ + getPanelInfo(id: string): any { + return this.panels.find((panel) => panel.id === id); + } + + /** + * Track by function for ngFor loops + * + * @param index + * @param item + */ + trackByFn(index: number, item: any): any { + return item.id || index; + } +} \ No newline at end of file diff --git a/frontend/src/app/modules/profile/profile.routes.ts b/frontend/src/app/modules/profile/profile.routes.ts new file mode 100644 index 00000000..695c4fc9 --- /dev/null +++ b/frontend/src/app/modules/profile/profile.routes.ts @@ -0,0 +1,9 @@ +import { Routes } from '@angular/router'; +import { ProfileComponent } from "./profile.component"; + +export default [ + { + path: '', + component: ProfileComponent, + }, +] as Routes; diff --git a/frontend/src/app/modules/profile/ui-settings/ui-settings.component.html b/frontend/src/app/modules/profile/ui-settings/ui-settings.component.html new file mode 100644 index 00000000..cf3135e8 --- /dev/null +++ b/frontend/src/app/modules/profile/ui-settings/ui-settings.component.html @@ -0,0 +1,331 @@ +
+ +
+
+ +
+ + +
SCHEME
+
+ +
+
+ +
+
+ Auto +
+
+ +
+
+ +
+
+ Dark +
+
+ +
+
+ +
+
+ Light +
+
+
+ +
+ + +
LAYOUT
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Compact +
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dense +
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Thin +
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Top +
+
+
+ +
+ + +
THEME
+
+ @for (theme of config.themes; track theme.id) { +
+
+
+ {{ theme.name }} +
+
+ } +
+ +
+
diff --git a/frontend/src/app/modules/profile/ui-settings/ui-settings.component.ts b/frontend/src/app/modules/profile/ui-settings/ui-settings.component.ts new file mode 100644 index 00000000..7b3110b8 --- /dev/null +++ b/frontend/src/app/modules/profile/ui-settings/ui-settings.component.ts @@ -0,0 +1,112 @@ +import { NgClass } from '@angular/common'; +import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { Router } from '@angular/router'; +import { + FuseConfig, + FuseConfigService, + Scheme, + Theme, + Themes, +} from '@fuse/services/config'; + +import { Subject, takeUntil } from 'rxjs'; + +@Component({ + selector: 'ui-settings', + templateUrl: './ui-settings.component.html', + encapsulation: ViewEncapsulation.None, + standalone: true, + imports: [ + MatIconModule, + MatButtonModule, + NgClass, + MatTooltipModule, + ], +}) +export class UiSettingsComponent implements OnInit, OnDestroy { + config: FuseConfig; + layout: string; + scheme: 'dark' | 'light'; + theme: string; + themes: Themes; + private _unsubscribeAll: Subject = new Subject(); + + /** + * Constructor + */ + constructor( + private _router: Router, + private _fuseConfigService: FuseConfigService + ) {} + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + // Subscribe to config changes + this._fuseConfigService.config$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((config: FuseConfig) => { + // Store the config + this.config = config; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Set the layout on the config + * + * @param layout + */ + setLayout(layout: string): void { + // Clear the 'layout' query param to allow layout changes + this._router + .navigate([], { + queryParams: { + layout: null, + }, + queryParamsHandling: 'merge', + }) + .then(() => { + // Set the config + this._fuseConfigService.config = { layout }; + }); + } + + /** + * Set the scheme on the config + * + * @param scheme + */ + setScheme(scheme: Scheme): void { + this._fuseConfigService.config = { scheme }; + } + + /** + * Set the theme on the config + * + * @param theme + */ + setTheme(theme: Theme): void { + this._fuseConfigService.config = { theme }; + } +} diff --git a/frontend/src/app/profile/profile-routing.module.ts b/frontend/src/app/profile/profile-routing.module.ts deleted file mode 100644 index c4c8ba92..00000000 --- a/frontend/src/app/profile/profile-routing.module.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { NgModule } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; -import { marker } from '@biesbjerg/ngx-translate-extract-marker'; - -import { ProfileComponent } from './profile.component'; - -const routes: Routes = [ - // Module is lazy loaded, see app-routing.module.ts - { path: '', component: ProfileComponent, data: { title: marker('Profile') } }, -]; - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule], - providers: [], -}) -export class ProfileRoutingModule {} diff --git a/frontend/src/app/profile/profile.component.html b/frontend/src/app/profile/profile.component.html deleted file mode 100644 index 67ea0e73..00000000 --- a/frontend/src/app/profile/profile.component.html +++ /dev/null @@ -1,163 +0,0 @@ -
-
- - -
- - ID - - - - - Email - - -
- -
Default Human In The Loop settings
-
- - Spend $USD - - - - Control loop iterations - - -
- -
LLM API Keys
-
-
- - Anthropic - - - - Fireworks - - - - Groq - - -
-
- - OpenAI - - - - TogetherAI - - - - DeepSeek - - -
-
- -
-
-
GitLab Configuration
-
- - Domain - - - - Token - - - - Top Level Groups (comma seperated) - - -
-
-
-
Jira Configuration
-
- - Base URL - - - - Email - - - - Token - - -
-
-
-
Slack Configuration
-
- - Slack Token - - - - Slack User ID - - - - Slack Webhook URL - - -
-
-
-
Perplexity
-
- - Perplexity Key - - -
-
-
-
GitHub Configuration
-
- - GitHub Token - - -
-
-
-
- - - -
-
-
diff --git a/frontend/src/app/profile/profile.component.scss b/frontend/src/app/profile/profile.component.scss deleted file mode 100644 index b0c2e6b2..00000000 --- a/frontend/src/app/profile/profile.component.scss +++ /dev/null @@ -1,30 +0,0 @@ -.horizontal-group { - display: flex; - justify-content: flex-start; - align-items: center; - > div { - flex: 0 1 auto; - margin-right: 20px; - } - > div:last-child { - margin-right: 0; - } -} - -.form-row label { - width: 30em; -} - -.section-title { - font-size: 20px; - font-weight: 400; - padding-top: 25px; - padding-bottom: 10px; -} -#enabled { - display: none; -} - -.mat-form-field { - padding-right: 10px; -} diff --git a/frontend/src/app/profile/profile.component.spec.ts b/frontend/src/app/profile/profile.component.spec.ts deleted file mode 100644 index 45f6f04a..00000000 --- a/frontend/src/app/profile/profile.component.spec.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { ProfileComponent } from './profile.component'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { RouterTestingModule } from '@angular/router/testing'; -import { ReactiveFormsModule } from '@angular/forms'; -import { MaterialModule } from '@app/material.module'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; - -describe('ProfileComponent', () => { - let component: ProfileComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - HttpClientTestingModule, - RouterTestingModule, - ReactiveFormsModule, - MaterialModule, - NoopAnimationsModule, - ], - declarations: [ProfileComponent], - }).compileComponents(); - - fixture = TestBed.createComponent(ProfileComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/frontend/src/app/profile/profile.component.ts b/frontend/src/app/profile/profile.component.ts deleted file mode 100644 index 2a948972..00000000 --- a/frontend/src/app/profile/profile.component.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { FormGroup, FormControl } from '@angular/forms'; -import { HttpClient } from '@angular/common/http'; -import { environment } from '@env/environment'; -import { MatSnackBar } from '@angular/material/snack-bar'; -import { LlmService } from '../shared/services/llm.service'; - -@Component({ - selector: 'app-profile', - templateUrl: './profile.component.html', - styleUrls: ['./profile.component.scss'], -}) -export class ProfileComponent implements OnInit { - profileForm: FormGroup; - constructor(private http: HttpClient, private snackBar: MatSnackBar, private llmService: LlmService) { - this.profileForm = this.createProfileForm(); - } - - private createProfileForm(): FormGroup { - return new FormGroup({ - id: new FormControl({ value: '', disabled: true }), - email: new FormControl(''), - enabled: new FormControl(false), - hilBudget: new FormControl(0), - hilCount: new FormControl(0), - llmConfig: new FormGroup({ - anthropicKey: new FormControl(''), - openaiKey: new FormControl(''), - groqKey: new FormControl(''), - togetheraiKey: new FormControl(''), - fireworksKey: new FormControl(''), - deepseekKey: new FormControl(''), - }), - functionConfig: new FormGroup({ - GitHub: new FormGroup({ - token: new FormControl(''), - }), - GitLab: new FormGroup({ - host: new FormControl(''), - token: new FormControl(''), - topLevelGroups: new FormControl(''), - }), - Jira: new FormGroup({ - baseUrl: new FormControl(''), - email: new FormControl(''), - token: new FormControl(''), - }), - Slack: new FormGroup({ - token: new FormControl(''), - userId: new FormControl(''), - webhookUrl: new FormControl(''), - }), - Perplexity: new FormGroup({ - key: new FormControl(''), - }), - }), - }); - } - - ngOnInit(): void { - this.loadUserProfile(); - } - - onSave(): void { - const updateUrl = `${environment.serverUrl}/profile/update`; - const formValue = this.profileForm.getRawValue(); - this.http.post(updateUrl, { user: formValue }).subscribe({ - next: () => { - this.snackBar.open('Profile updated', 'Close', { duration: 3000 }); - this.llmService.clearCache(); - this.loadLlmList(); - }, - error: (error) => { - this.snackBar.open('Failed to save profile.', 'Close', { duration: 3000 }); - console.log(error); - }, - }); - } - - private loadUserProfile(): void { - console.log('Loading user profile...'); - const profileUrl = `${environment.serverUrl}/profile/view`; - this.http.get(profileUrl).subscribe( - (response: any) => { - console.log(response.data); - this.profileForm.patchValue(response.data); - }, - (error) => { - console.log(error); - this.snackBar.open('Failed to load user profile', 'Close', { duration: 3000 }); - } - ); - } - - private loadLlmList(): void { - this.llmService.getLlms().subscribe({ - next: (llms) => { - console.log('LLM list loaded:', llms); - }, - error: (error) => { - console.error('Failed to load LLM list:', error); - this.snackBar.open('Failed to load LLM list', 'Close', { duration: 3000 }); - }, - }); - } -} diff --git a/frontend/src/app/profile/profile.module.ts b/frontend/src/app/profile/profile.module.ts deleted file mode 100644 index aea709d4..00000000 --- a/frontend/src/app/profile/profile.module.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { TranslateModule } from '@ngx-translate/core'; -import { FlexLayoutModule } from '@angular/flex-layout'; -import { MaterialModule } from '@app/material.module'; -import { ProfileRoutingModule } from './profile-routing.module'; -import { ProfileComponent } from './profile.component'; -import { MatSnackBarModule } from '@angular/material/snack-bar'; - -@NgModule({ - imports: [CommonModule, TranslateModule, MatSnackBarModule, FlexLayoutModule, MaterialModule, ProfileRoutingModule], - declarations: [ProfileComponent], -}) -export class ProfileModule {} diff --git a/frontend/src/app/runAgent/runAgent-routing.module.ts b/frontend/src/app/runAgent/runAgent-routing.module.ts deleted file mode 100644 index c5af3d5b..00000000 --- a/frontend/src/app/runAgent/runAgent-routing.module.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { NgModule } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; -import { marker } from '@biesbjerg/ngx-translate-extract-marker'; - -import { RunAgentComponent } from './runAgent.component'; - -const routes: Routes = [ - // Module is lazy loaded, see app-routing.module.ts - { path: '', component: RunAgentComponent, data: { title: marker('New Agent') } }, -]; - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule], - providers: [], -}) -export class RunAgentRoutingModule {} diff --git a/frontend/src/app/runAgent/runAgent.component.html b/frontend/src/app/runAgent/runAgent.component.html deleted file mode 100644 index d691ac47..00000000 --- a/frontend/src/app/runAgent/runAgent.component.html +++ /dev/null @@ -1,115 +0,0 @@ -
-
- - -
- - Name - - -
- -
- - Function calling type - - Code Generation - XML - Native - - -
- -
- - Prompt - - -
- -
LLMs
-
-
- - Easy - - - {{ llm.name }} - - - -
-
- - Medium - - - {{ llm.name }} - - - -
-
- - Hard - - - {{ llm.name }} - - - -
-
- - -
Functions
- -
-
- {{ func }} -
-
- -
Human In The Loop
- -
- - Budget $USD - - - - Agent control loop iterations - - -
-
- - - -
-
-
diff --git a/frontend/src/app/runAgent/runAgent.component.scss b/frontend/src/app/runAgent/runAgent.component.scss deleted file mode 100644 index 1e351a90..00000000 --- a/frontend/src/app/runAgent/runAgent.component.scss +++ /dev/null @@ -1,46 +0,0 @@ -.horizontal-group { - display: flex; - justify-content: flex-start; - align-items: center; - > div:not(:first-child) { - margin-left: 20px; - } -} - -.function-item { - display: flex; - align-items: center; - padding-right: 5px; -} - -.form-row label { - width: 30em; -} - -.presets a { - padding-right: 5px; -} -.functions-grid { - display: grid; - grid-template-columns: repeat(3, minmax(auto, max-content)); - gap: 10px; -} - -.promptField, -.nameField { - width: 500px; -} -.promptField { - height: 180px; -} - -textarea.mat-input-element { - height: 100% !important; -} - -.section-title { - font-size: 20px; - font-weight: 400; - padding-top: 25px; - padding-bottom: 10px; -} diff --git a/frontend/src/app/runAgent/runAgent.component.spec.ts b/frontend/src/app/runAgent/runAgent.component.spec.ts deleted file mode 100644 index 5b7e78fa..00000000 --- a/frontend/src/app/runAgent/runAgent.component.spec.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { ReactiveFormsModule } from '@angular/forms'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { MatSnackBarModule } from '@angular/material/snack-bar'; -import { RunAgentComponent } from './runAgent.component'; -import { MaterialModule } from '@app/material.module'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; - -describe('RunAgentComponent', () => { - let component: RunAgentComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [RunAgentComponent], - imports: [ReactiveFormsModule, HttpClientTestingModule, NoopAnimationsModule, MatSnackBarModule, MaterialModule], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(RunAgentComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should have a valid form when all fields are filled', () => { - component.runAgentForm.patchValue({ - name: 'Test Agent', - userPrompt: 'Test prompt', - type: 'xml', - llmEasy: 'test-llm', - llmMedium: 'test-llm', - llmHard: 'test-llm', - budget: 10, - count: 5, - }); - expect(component.runAgentForm.valid).toBeTruthy(); - }); - - it('should have "codegen" as the default type', () => { - expect(component.runAgentForm.get('type')?.value).toBe('codegen'); - }); - - it('should allow changing the type to "xml"', () => { - component.runAgentForm.patchValue({ type: 'xml' }); - expect(component.runAgentForm.get('type')?.value).toBe('xml'); - }); -}); diff --git a/frontend/src/app/runAgent/runAgent.component.ts b/frontend/src/app/runAgent/runAgent.component.ts deleted file mode 100644 index 7f4be46f..00000000 --- a/frontend/src/app/runAgent/runAgent.component.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { map } from 'rxjs/operators'; -import { FormGroup, FormControl, Validators } from '@angular/forms'; -import { MatSnackBar } from '@angular/material/snack-bar'; -import { Router } from '@angular/router'; -import { environment } from '@env/environment'; -import { AgentEventService } from '@app/agent-event.service'; -import { LlmService } from '@app/shared/services/llm.service'; -import { AgentType } from '@shared'; - -interface StartAgentResponse { - data: { - agentId: string; - }; -} - -const defaultType: AgentType = 'codegen'; - -@Component({ - selector: 'app-run-agent', - templateUrl: './runAgent.component.html', - styleUrls: ['./runAgent.component.scss'], -}) -export class RunAgentComponent implements OnInit { - functions: string[] = []; - llms: any[] = []; - runAgentForm: FormGroup; - isSubmitting: boolean = false; - - constructor( - private http: HttpClient, - private snackBar: MatSnackBar, - private router: Router, - private agentEventService: AgentEventService, - private llmService: LlmService - ) { - this.runAgentForm = new FormGroup({ - name: new FormControl('', Validators.required), - userPrompt: new FormControl('', Validators.required), - type: new FormControl(defaultType, Validators.required), - llmEasy: new FormControl('', Validators.required), - llmMedium: new FormControl('', Validators.required), - llmHard: new FormControl('', Validators.required), - budget: new FormControl(0, [Validators.required, Validators.min(0)]), - count: new FormControl(0, [Validators.required, Validators.min(0), Validators.pattern('^[0-9]*$')]), - }); - } - setPreset(preset: string): boolean { - console.log(`setPreset ${preset}`); - const presets = { - 'claude-vertex': { - easy: 'anthropic-vertex:claude-3-haiku', - medium: 'anthropic-vertex:claude-3-5-sonnet', - hard: 'anthropic-vertex:claude-3-5-sonnet', - }, - claude: { - easy: 'anthropic:claude-3-haiku', - medium: 'anthropic:claude-3-5-sonnet', - hard: 'anthropic:claude-3-5-sonnet', - }, - gemini: { easy: 'vertex:gemini-1.5-flash', medium: 'vertex:gemini-1.5-flash', hard: 'vertex:gemini-1.5-pro' }, - openai: { easy: 'openai:gpt-4o', medium: 'openai:gpt-4o', hard: 'openai:gpt-4o' }, - }; - const selection = presets[preset]; - if (selection) { - const ids = this.llms.map((llm) => llm.id); - this.runAgentForm.controls['llmEasy'].setValue(ids.find((id) => id.startsWith(selection.easy))); - this.runAgentForm.controls['llmMedium'].setValue(ids.find((id) => id.startsWith(selection.medium))); - this.runAgentForm.controls['llmHard'].setValue(ids.find((id) => id.startsWith(selection.hard))); - } - return false; - } - - ngOnInit(): void { - this.http - .get<{ data: string[] }>(`${environment.serverUrl}/agent/v1/functions`) - .pipe( - map((response) => { - console.log(response); - return (response.data as string[]).filter((name) => name !== 'Agent'); - }) - ) - .subscribe((functions) => { - this.functions = functions.sort(); - // Dynamically add form controls for each function - functions.forEach((tool, index) => { - (this.runAgentForm as FormGroup).addControl('function' + index, new FormControl(false)); - }); - }); - - this.llmService.getLlms().subscribe({ - next: (llms) => { - this.llms = llms; - }, - error: (error) => { - console.error('Error fetching LLMs:', error); - this.snackBar.open('Failed to load LLMs', 'Close', { duration: 3000 }); - }, - }); - - this.loadUserProfile(); - } - - private loadUserProfile(): void { - const profileUrl = `${environment.serverUrl}/profile/view`; - this.http.get(profileUrl).subscribe( - (response: any) => { - console.log(response.data); - this.runAgentForm.controls['budget'].setValue(response.data.hilBudget); - this.runAgentForm.controls['count'].setValue(response.data.hilCount); - }, - (error) => { - console.log(error); - this.snackBar.open('Failed to load user profile', 'Close', { duration: 3000 }); - } - ); - } - - // ... rest of the component - onSubmit(): void { - if (!this.runAgentForm.valid) return; - // Implement the logic to handle form submission - console.log('Form submitted', this.runAgentForm.value); - const selectedFunctions: string[] = this.functions - .filter((_, index) => this.runAgentForm.value['function' + index]) - .map((tool, _) => tool); - this.http - .post(`${environment.serverUrl}/agent/v1/start`, { - name: this.runAgentForm.value.name, - userPrompt: this.runAgentForm.value.userPrompt, - type: this.runAgentForm.value.type, - // systemPrompt: this.runAgentForm.value.systemPrompt, - functions: selectedFunctions, - budget: this.runAgentForm.value.budget, - count: this.runAgentForm.value.count, - llmEasy: this.runAgentForm.value.llmEasy, - llmMedium: this.runAgentForm.value.llmMedium, - llmHard: this.runAgentForm.value.llmHard, - }) - .subscribe({ - next: (response) => { - this.snackBar.open('Agent started', 'Close', { duration: 3000 }); - this.router.navigate(['/agent', response.data.agentId]).catch((e) => console.error); // Assuming the response contains the agentId - }, - error: (error) => { - this.snackBar.open(`Error ${error.message}`, 'Close', { duration: 3000 }); - console.error('Error starting agent', error); - }, - }); - } -} diff --git a/frontend/src/app/runAgent/runAgent.module.ts b/frontend/src/app/runAgent/runAgent.module.ts deleted file mode 100644 index 991a64bd..00000000 --- a/frontend/src/app/runAgent/runAgent.module.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { TranslateModule } from '@ngx-translate/core'; -import { FlexLayoutModule } from '@angular/flex-layout'; - -import { MaterialModule } from '@app/material.module'; -import { RunAgentRoutingModule } from './runAgent-routing.module'; -import { RunAgentComponent } from './runAgent.component'; - -@NgModule({ - imports: [CommonModule, TranslateModule, FlexLayoutModule, MaterialModule, RunAgentRoutingModule], - declarations: [RunAgentComponent], -}) -export class RunAgentModule {} diff --git a/frontend/src/app/shared/confirm-dialog/confirm-dialog.component.ts b/frontend/src/app/shared/confirm-dialog/confirm-dialog.component.ts deleted file mode 100644 index 4b5908d2..00000000 --- a/frontend/src/app/shared/confirm-dialog/confirm-dialog.component.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Component, Inject } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { MatButtonModule } from '@angular/material/button'; -import { MatDialogModule } from '@angular/material/dialog'; - -@Component({ - selector: 'app-confirm-dialog', - template: ` -

{{ data.title }}

- {{ data.message }} - - - - - `, - standalone: true, - imports: [MatDialogModule, MatButtonModule], - styles: [ - ` - :host { - font-family: Arial, sans-serif; - } - h2 { - font-size: 20px; - font-weight: bold; - } - mat-dialog-content { - font-size: 16px; - } - `, - ], -}) -export class ConfirmDialogComponent { - constructor( - public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: { title: string; message: string } - ) {} -} diff --git a/frontend/src/app/shell/shell.component.html b/frontend/src/app/shell/shell.component.html deleted file mode 100644 index c8ca5250..00000000 --- a/frontend/src/app/shell/shell.component.html +++ /dev/null @@ -1,73 +0,0 @@ -
- - - - APP_NAME -
- -
- -
- - - - {{ title }} - - - -
-
diff --git a/frontend/src/app/shell/shell.component.scss b/frontend/src/app/shell/shell.component.scss deleted file mode 100644 index 3e31a9e1..00000000 --- a/frontend/src/app/shell/shell.component.scss +++ /dev/null @@ -1,39 +0,0 @@ -:host { - display: flex; - flex: 1; -} - -.mat-sidenav { - min-width: 190px; - max-width: 28%; -} - -.mat-list-base .mat-list-item, -.mat-list-base .mat-list-option { - height: 46px; -} - -.mat-toolbar-row, -.mat-toolbar-single-row { - padding-left: 25px; -} - -.has-border { - border-right: 1px solid rgb(0 0 0 / 12%); -} - -.mat-list { - padding-top: 0; -} - -.mat-list-item { - text-decoration: none; - - &:hover { - background: rgb(0 0 0 / 5%); - } -} - -.menu-button { - margin-right: 1rem; -} diff --git a/frontend/src/app/shell/shell.component.spec.ts b/frontend/src/app/shell/shell.component.spec.ts deleted file mode 100644 index 9fcb124e..00000000 --- a/frontend/src/app/shell/shell.component.spec.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; -import { TranslateModule } from '@ngx-translate/core'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { FlexLayoutModule } from '@angular/flex-layout'; -import { MaterialModule } from '@app/material.module'; - -import { AuthenticationService, CredentialsService } from '@app/auth'; -import { MockAuthenticationService } from '@app/auth/authentication.service.mock'; -import { MockCredentialsService } from '@app/auth/credentials.service.mock'; - -import { I18nModule } from '@app/i18n'; -import { ShellComponent } from './shell.component'; - -describe('ShellComponent', () => { - let component: ShellComponent; - let fixture: ComponentFixture; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [ - TranslateModule.forRoot(), - I18nModule, - BrowserAnimationsModule, - FlexLayoutModule, - MaterialModule, - RouterTestingModule, - ], - providers: [ - { provide: AuthenticationService, useClass: MockAuthenticationService }, - { provide: CredentialsService, useClass: MockCredentialsService }, - ], - declarations: [ShellComponent], - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(ShellComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/frontend/src/app/shell/shell.component.ts b/frontend/src/app/shell/shell.component.ts deleted file mode 100644 index 4188c728..00000000 --- a/frontend/src/app/shell/shell.component.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Title } from '@angular/platform-browser'; -import { Component, OnInit } from '@angular/core'; -import { Router } from '@angular/router'; -import { Breakpoints, BreakpointObserver } from '@angular/cdk/layout'; - -import { AuthenticationService, CredentialsService } from '@app/auth'; - -@Component({ - selector: 'app-shell', - templateUrl: './shell.component.html', - styleUrls: ['./shell.component.scss'], -}) -export class ShellComponent implements OnInit { - constructor( - private router: Router, - private titleService: Title, - private authenticationService: AuthenticationService, - private credentialsService: CredentialsService, - private breakpoint: BreakpointObserver - ) {} - - ngOnInit() {} - - logout() { - this.authenticationService.logout().subscribe(() => this.router.navigate(['/login'], { replaceUrl: true })); - } - - get username(): string | null { - const credentials = this.credentialsService.credentials; - return credentials ? credentials.username : null; - } - - get isMobile(): boolean { - return this.breakpoint.isMatched(Breakpoints.Small) || this.breakpoint.isMatched(Breakpoints.XSmall); - } - - get title(): string { - return this.titleService.getTitle(); - } -} diff --git a/frontend/src/app/shell/shell.module.ts b/frontend/src/app/shell/shell.module.ts deleted file mode 100644 index 7cbb0c69..00000000 --- a/frontend/src/app/shell/shell.module.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { TranslateModule } from '@ngx-translate/core'; -import { RouterModule } from '@angular/router'; -import { FlexLayoutModule } from '@angular/flex-layout'; - -import { I18nModule } from '@app/i18n'; -import { MaterialModule } from '@app/material.module'; -import { AuthModule } from '@app/auth'; -import { ShellComponent } from './shell.component'; - -@NgModule({ - imports: [CommonModule, TranslateModule, FlexLayoutModule, MaterialModule, AuthModule, I18nModule, RouterModule], - declarations: [ShellComponent], -}) -export class ShellModule {} diff --git a/frontend/src/app/shell/shell.service.spec.ts b/frontend/src/app/shell/shell.service.spec.ts deleted file mode 100644 index fe32be85..00000000 --- a/frontend/src/app/shell/shell.service.spec.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { TestBed, inject } from '@angular/core/testing'; - -import { AuthenticationGuard, AuthenticationService } from '@app/auth'; -import { MockAuthenticationService } from '@app/auth/authentication.service.mock'; -import { ShellComponent } from './shell.component'; -import { Shell } from './shell.service'; - -describe('Shell', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [ShellComponent], - providers: [AuthenticationGuard, { provide: AuthenticationService, useClass: MockAuthenticationService }], - }); - }); - - describe('childRoutes', () => { - it('should create routes as children of shell', () => { - // Prepare - const testRoutes = [{ path: 'test' }]; - - // Act - const result = Shell.childRoutes(testRoutes); - - // Assert - expect(result.path).toBe(''); - expect(result.children).toBe(testRoutes); - expect(result.component).toBe(ShellComponent); - }); - }); -}); diff --git a/frontend/src/app/shell/shell.service.ts b/frontend/src/app/shell/shell.service.ts deleted file mode 100644 index e80078e4..00000000 --- a/frontend/src/app/shell/shell.service.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Routes, Route } from '@angular/router'; - -import { AuthenticationGuard } from '@app/auth'; -import { ShellComponent } from './shell.component'; - -/** - * Provides helper methods to create routes. - */ -export class Shell { - /** - * Creates routes using the shell component and authentication. - * @param routes The routes to add. - * @return The new route using shell as the base. - */ - static childRoutes(routes: Routes): Route { - return { - path: '', - component: ShellComponent, - children: routes, - canActivate: [AuthenticationGuard], - }; - } -} diff --git a/frontend/src/apple-touch-icon.png b/frontend/src/apple-touch-icon.png deleted file mode 100644 index 775c0fe5..00000000 Binary files a/frontend/src/apple-touch-icon.png and /dev/null differ diff --git a/frontend/src/assets/ngx-rocket-logo.png b/frontend/src/assets/ngx-rocket-logo.png deleted file mode 100644 index 4f17d958..00000000 Binary files a/frontend/src/assets/ngx-rocket-logo.png and /dev/null differ diff --git a/frontend/src/environments/.env.ts b/frontend/src/environments/.env.ts new file mode 100644 index 00000000..951fa011 --- /dev/null +++ b/frontend/src/environments/.env.ts @@ -0,0 +1,7 @@ + +export const env = { + SERVER_URL: '', + GCLOUD_PROJECT: '', + FIRESTORE_DATABASE: '', + AUTH: '' +} \ No newline at end of file diff --git a/frontend/src/environments/environment.prod.ts b/frontend/src/environments/environment.prod.ts index 0694520c..aacbf467 100644 --- a/frontend/src/environments/environment.prod.ts +++ b/frontend/src/environments/environment.prod.ts @@ -9,11 +9,9 @@ import { env } from './.env'; export const environment = { production: true, - version: env['npm_package_version'], - defaultLanguage: 'en-US', - supportedLanguages: ['en-US'], serverUrl: env['SERVER_URL'] || 'http://localhost:3000/api', gcpProject: env['GCLOUD_PROJECT'], firestoreDb: env['FIRESTORE_DATABASE'], auth: env['AUTH'], + apiBaseUrl: 'https://api.yourdomain.com', // Adjust this URL for production }; diff --git a/frontend/src/environments/environment.ts b/frontend/src/environments/environment.ts index bfc049a4..d21b00e6 100644 --- a/frontend/src/environments/environment.ts +++ b/frontend/src/environments/environment.ts @@ -13,20 +13,9 @@ import { env } from './.env'; export const environment = { production: false, - version: env['npm_package_version'] + '-dev', - defaultLanguage: 'en-US', - supportedLanguages: ['en-US'], serverUrl: env['SERVER_URL'] || 'http://localhost:3000/api', gcpProject: env['GCLOUD_PROJECT'], firestoreDb: env['FIRESTORE_DATABASE'], auth: env['AUTH'], + apiBaseUrl: 'http://localhost:3000/api/', // Adjust this URL as needed for local development }; - -/* - * For easier debugging in development mode, you can import the following file - * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. - * - * This import should be commented out in production mode because it will have a negative impact - * on performance if an error is thrown. - */ -// import 'zone.js/plugins/zone-error'; // Included with Angular CLI. diff --git a/frontend/src/favicon.ico b/frontend/src/favicon.ico deleted file mode 100644 index f5ddd107..00000000 Binary files a/frontend/src/favicon.ico and /dev/null differ diff --git a/frontend/src/index.html b/frontend/src/index.html index 70cf0b60..a4c5e57b 100644 --- a/frontend/src/index.html +++ b/frontend/src/index.html @@ -1,27 +1,60 @@ - + - - - - - sophia  |  ai - - - - - - - - - - - - + + SOPHIA | AI + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+ + + + diff --git a/frontend/src/main.scss b/frontend/src/main.scss deleted file mode 100644 index 6e67038e..00000000 --- a/frontend/src/main.scss +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Entry point of global application style. - * Component-specific style should not go here and be included directly as part of the components. - */ - -// Theme variables, must be included before the libraries to allow overriding defaults -@import "theme/theme-variables"; - -// 3rd party libraries -@import "~material-design-icons-iconfont/src/material-design-icons"; - -// Angular Material custom theme -// The mixins below must be included once so we separated them from the variables -@import "~@angular/material/theming"; - -// Include the common styles for Angular Material. We include this here so that you only -// have to load a single css file for Angular Material in your app. -// Be sure that you only ever include this mixin once! -@include mat-core(); - -// Include theme styles for core and each component used in your app. -// Alternatively, you can import and @include the theme mixins for each component -// that you are using. -@include angular-material-theme($app-theme); - -// Theme customization -@import "theme/theme"; - -.mat-toolbar-row, -.mat-toolbar-single-row { - height: 50px; -} - -.mat-toolbar, -.mat-toolbar h1, -.mat-toolbar h2, -.mat-toolbar h3, -.mat-toolbar h4, -.mat-toolbar h5, -.mat-toolbar h6 { - font-weight: 400; -} - -.mat-card-title { - font-weight: 400; -} diff --git a/frontend/src/main.ts b/frontend/src/main.ts index a699f943..147a38eb 100644 --- a/frontend/src/main.ts +++ b/frontend/src/main.ts @@ -1,19 +1,7 @@ -/* - * Entry point of the application. - * Only platform bootstrapping code should be here. - * For app-specific initialization, use `app/app.component.ts`. - */ +import { bootstrapApplication } from '@angular/platform-browser'; +import { AppComponent } from 'app/app.component'; +import { appConfig } from 'app/app.config'; -import { enableProdMode } from '@angular/core'; -import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; - -import { AppModule } from '@app/app.module'; -import { environment } from '@env/environment'; - -if (environment.production) { - enableProdMode(); -} - -platformBrowserDynamic() - .bootstrapModule(AppModule) - .catch((err) => console.error(err)); +bootstrapApplication(AppComponent, appConfig).catch((err) => + console.error(err) +); diff --git a/frontend/src/polyfills.ts b/frontend/src/polyfills.ts deleted file mode 100644 index 38d693df..00000000 --- a/frontend/src/polyfills.ts +++ /dev/null @@ -1,57 +0,0 @@ -/*************************************************************************************************** - * Load `$localize` onto the global scope - used if i18n tags appear in Angular templates. - */ -import '@angular/localize/init'; - -/** - * This file includes polyfills needed by Angular and is loaded before the app. - * You can add your own extra polyfills to this file. - * - * This file is divided into 2 sections: - * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. - * 2. Application imports. Files imported after ZoneJS that should be loaded before your main - * file. - * - * The current setup is for so-called "evergreen" browsers; the last versions of browsers that - * automatically update themselves. This includes recent versions of Safari, Chrome (including - * Opera), Edge on the desktop, and iOS and Chrome on mobile. - * - * Learn more in https://angular.io/guide/browser-support - */ - -/*************************************************************************************************** - * BROWSER POLYFILLS - */ - -/** - * By default, zone.js will patch all possible macroTask and DomEvents - * user can disable parts of macroTask/DomEvents patch by setting following flags - * because those flags need to be set before `zone.js` being loaded, and webpack - * will put import in the top of bundle, so user need to create a separate file - * in this directory (for example: zone-flags.ts), and put the following flags - * into that file, and then add the following code before importing zone.js. - * import './zone-flags'; - * - * The flags allowed in zone-flags.ts are listed here. - * - * The following flags will work for all browsers. - * - * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame - * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick - * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames - * - * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js - * with the following flag, it will bypass `zone.js` patch for IE/Edge - * - * (window as any).__Zone_enable_cross_context_check = true; - * - */ - -/*************************************************************************************************** - * Zone JS is required by default for Angular itself. - */ -import 'zone.js'; // Included with Angular CLI. - -/*************************************************************************************************** - * APPLICATION IMPORTS - */ diff --git a/frontend/src/robots.txt b/frontend/src/robots.txt deleted file mode 100755 index d0e5f1be..00000000 --- a/frontend/src/robots.txt +++ /dev/null @@ -1,5 +0,0 @@ -# www.robotstxt.org/ - -# Allow crawling of all content -User-agent: * -Disallow: diff --git a/frontend/src/setup-jest.ts b/frontend/src/setup-jest.ts deleted file mode 100644 index 7bc803f6..00000000 --- a/frontend/src/setup-jest.ts +++ /dev/null @@ -1,48 +0,0 @@ -import 'jest-preset-angular'; - -/* global mocks for jsdom */ -const storageMock = () => { - let storage: { [key: string]: string } = {}; - return { - getItem: (key: string) => (key in storage ? storage[key] : null), - setItem: (key: string, value: string) => (storage[key] = value || ''), - removeItem: (key: string) => delete storage[key], - clear: () => (storage = {}), - }; -}; - -Object.defineProperty(window, 'localStorage', { value: storageMock() }); -Object.defineProperty(window, 'sessionStorage', { value: storageMock() }); -Object.defineProperty(window, 'getComputedStyle', { - value: () => ['-webkit-appearance'], -}); - -Object.defineProperty(document.body.style, 'transform', { - value: () => { - return { - enumerable: true, - configurable: true, - }; - }, -}); - -Object.defineProperty(window, 'getComputedStyle', { - value: () => ({ - getPropertyValue: (prop: any) => { - return ''; - }, - }), -}); - -Object.defineProperty(window, 'matchMedia', { - value: (query: any) => ({ - matches: false, - media: query, - onchange: null as any, - addListener: () => {}, - removeListener: () => {}, - }), -}); - -/* output shorter and more meaningful Zone error stack traces */ -// Error.stackTraceLimit = 2; diff --git a/frontend/src/styles/styles.scss b/frontend/src/styles/styles.scss new file mode 100644 index 00000000..f1ed5ecc --- /dev/null +++ b/frontend/src/styles/styles.scss @@ -0,0 +1,4 @@ +/* ----------------------------------------------------------------------------------------------------- */ +/* @ Import/write your custom styles here. +/* @ Styles from this file will override 'vendors.scss' and Fuse's base styles. +/* ----------------------------------------------------------------------------------------------------- */ diff --git a/frontend/src/styles/tailwind.scss b/frontend/src/styles/tailwind.scss new file mode 100644 index 00000000..08c702c6 --- /dev/null +++ b/frontend/src/styles/tailwind.scss @@ -0,0 +1,4 @@ +/* ----------------------------------------------------------------------------------------------------- */ +/* @ Main Tailwind file for injecting utilities. +/* ----------------------------------------------------------------------------------------------------- */ +@tailwind utilities; diff --git a/frontend/src/styles/vendors.scss b/frontend/src/styles/vendors.scss new file mode 100644 index 00000000..9cad066f --- /dev/null +++ b/frontend/src/styles/vendors.scss @@ -0,0 +1,9 @@ +/* ----------------------------------------------------------------------------------------------------- */ +/* @ Import third party library styles here. +/* ----------------------------------------------------------------------------------------------------- */ + +/* Perfect scrollbar */ +@import 'perfect-scrollbar/css/perfect-scrollbar.css'; + +/* Quill */ +@import 'quill/dist/quill.snow.css'; diff --git a/frontend/src/test-config.helper.ts b/frontend/src/test-config.helper.ts deleted file mode 100644 index 4bec94ea..00000000 --- a/frontend/src/test-config.helper.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -type CompilerOptions = Partial<{ - providers: any[]; - useJit: boolean; - preserveWhitespaces: boolean; -}>; -export type ConfigureFn = (testBed: typeof TestBed) => void; - -export const configureTests = (configure: ConfigureFn, compilerOptions: CompilerOptions = {}) => { - const compilerConfig: CompilerOptions = { - preserveWhitespaces: false, - ...compilerOptions, - }; - - const configuredTestBed = TestBed.configureCompiler(compilerConfig); - - configure(configuredTestBed); - - return configuredTestBed.compileComponents().then(() => configuredTestBed); -}; diff --git a/frontend/src/theme/theme-variables.scss b/frontend/src/theme/theme-variables.scss deleted file mode 100644 index eff2a869..00000000 --- a/frontend/src/theme/theme-variables.scss +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Application global variables. - */ - -// Angular Material custom theme -// See https://material.angular.io/guide/theming for more details. - -// You can also read https://medium.com/@tomastrajan/the-complete-guide-to-angular-material-themes-4d165a9d24d1 -// for more insight about Angular Material theming. -@use "@angular/material" as mat; - -/* -@include mat.core(); - -// Define a dark theme -$dark-primary: mat.define-palette(mat.$indigo-palette); -$dark-accent: mat.define-palette(mat.$blue-grey-palette); -$dark-dark: mat.define-palette(mat.$grey-palette); -$dark-theme: mat.define-dark-theme(( - color: ( - primary: $dark-primary, - accent: $dark-accent, - dark: $dark-dark, - ) -)); - -// Apply the dark theme by default -@include mat.core-theme($dark-theme); -@include mat.button-theme($dark-theme); -//*/ - -@import "~@angular/material/theming"; - -// Define the palettes for your theme using the Material Design palettes available in palette.scss -// (imported above). For each palette, you can optionally specify a default, lighter, and darker -// hue. -$app-primary: mat-palette($mat-indigo, 700, 600, 500); -// stylelint-disable-next-line value-keyword-case -//$app-accent: mat-palette($mat-pink, A200, A100, A400); -$app-accent: mat-palette($mat-grey, 900, 700, 600); - -// The warn palette is optional (defaults to red). -$app-warn: mat-palette($mat-red); - -// Create the theme object (a Sass map containing all of the palettes). -$app-theme: mat-light-theme($app-primary, $app-accent, $app-warn); - -// Material design icons font path -$material-design-icons-font-directory-path: "~material-design-icons-iconfont/dist/fonts/"; diff --git a/frontend/src/theme/theme.scss b/frontend/src/theme/theme.scss deleted file mode 100644 index 18bbe887..00000000 --- a/frontend/src/theme/theme.scss +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Global application theme. - * Framework overrides and customization goes here. - */ - -// stylelint-disable-next-line selector-max-universal -* { - box-sizing: border-box; -} - -html, -body { - display: flex; - flex-direction: column; - margin: 0; - height: 100%; -} diff --git a/frontend/src/translations/en-US.json b/frontend/src/translations/en-US.json deleted file mode 100755 index 0f923bfb..00000000 --- a/frontend/src/translations/en-US.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "APP_NAME": "sophia  |  ai", - "About": "About", - "Hello world !": "Hello world !", - "Home": "Home", - "Logged in as": "Logged in as", - "Login": "Login", - "Logout": "Logout", - "Password": "Password", - "Password is required": "Password is required", - "Username": "Username", - "Username is required": "Username is required", - "Username or password incorrect.": "Username or password incorrect.", - "Remember me": "Remember me", - "Version": "Version" -} diff --git a/frontend/src/typings.d.ts b/frontend/src/typings.d.ts deleted file mode 100644 index 7306c36f..00000000 --- a/frontend/src/typings.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Extra typings definitions - */ - -// Allow .json files imports -declare module '*.json'; - -// SystemJS module definition -declare var module: NodeModule; -interface NodeModule { - id: string; -} diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js new file mode 100644 index 00000000..12d97a6b --- /dev/null +++ b/frontend/tailwind.config.js @@ -0,0 +1,301 @@ +const path = require('path'); +const colors = require('tailwindcss/colors'); +const defaultTheme = require('tailwindcss/defaultTheme'); +const generatePalette = require( + path.resolve(__dirname, 'src/@fuse/tailwind/utils/generate-palette') +); + +/** + * Custom palettes + * + * Uses the generatePalette helper method to generate + * Tailwind-like color palettes automatically + */ +const customPalettes = { + brand: generatePalette('#2196F3'), +}; + +/** + * Themes + */ +const themes = { + // Default theme is required for theming system to work correctly! + default: { + primary: { + ...colors.indigo, + DEFAULT: colors.indigo[600], + }, + accent: { + ...colors.slate, + DEFAULT: colors.slate[800], + }, + warn: { + ...colors.red, + DEFAULT: colors.red[600], + }, + 'on-warn': { + 500: colors.red['50'], + }, + }, + // Rest of the themes will use the 'default' as the base + // theme and will extend it with their given configuration. + brand: { + primary: customPalettes.brand, + }, + teal: { + primary: { + ...colors.teal, + DEFAULT: colors.teal[600], + }, + }, + rose: { + primary: colors.rose, + }, + purple: { + primary: { + ...colors.purple, + DEFAULT: colors.purple[600], + }, + }, + amber: { + primary: colors.amber, + }, +}; + +/** + * Tailwind configuration + */ +const config = { + darkMode: 'class', + content: ['./src/**/*.{html,scss,ts}'], + important: true, + theme: { + fontSize: { + xs: '0.625rem', + sm: '0.75rem', + md: '0.8125rem', + base: '0.875rem', + lg: '1rem', + xl: '1.125rem', + '2xl': '1.25rem', + '3xl': '1.5rem', + '4xl': '2rem', + '5xl': '2.25rem', + '6xl': '2.5rem', + '7xl': '3rem', + '8xl': '4rem', + '9xl': '6rem', + '10xl': '8rem', + }, + screens: { + sm: '600px', + md: '960px', + lg: '1280px', + xl: '1440px', + }, + extend: { + animation: { + 'spin-slow': 'spin 3s linear infinite', + }, + colors: { + gray: colors.slate, + }, + flex: { + 0: '0 0 auto', + }, + fontFamily: { + sans: `"Inter var", ${defaultTheme.fontFamily.sans.join(',')}`, + mono: `"IBM Plex Mono", ${defaultTheme.fontFamily.mono.join(',')}`, + }, + opacity: { + 12: '0.12', + 38: '0.38', + 87: '0.87', + }, + rotate: { + '-270': '270deg', + 15: '15deg', + 30: '30deg', + 60: '60deg', + 270: '270deg', + }, + scale: { + '-1': '-1', + }, + zIndex: { + '-1': -1, + 49: 49, + 60: 60, + 70: 70, + 80: 80, + 90: 90, + 99: 99, + 999: 999, + 9999: 9999, + 99999: 99999, + }, + spacing: { + 13: '3.25rem', + 15: '3.75rem', + 18: '4.5rem', + 22: '5.5rem', + 26: '6.5rem', + 30: '7.5rem', + 50: '12.5rem', + 90: '22.5rem', + + // Bigger values + 100: '25rem', + 120: '30rem', + 128: '32rem', + 140: '35rem', + 160: '40rem', + 180: '45rem', + 192: '48rem', + 200: '50rem', + 240: '60rem', + 256: '64rem', + 280: '70rem', + 320: '80rem', + 360: '90rem', + 400: '100rem', + 480: '120rem', + + // Fractional values + '1/2': '50%', + '1/3': '33.333333%', + '2/3': '66.666667%', + '1/4': '25%', + '2/4': '50%', + '3/4': '75%', + }, + minHeight: ({ theme }) => ({ + ...theme('spacing'), + }), + maxHeight: { + none: 'none', + }, + minWidth: ({ theme }) => ({ + ...theme('spacing'), + screen: '100vw', + }), + maxWidth: ({ theme }) => ({ + ...theme('spacing'), + screen: '100vw', + }), + transitionDuration: { + 400: '400ms', + }, + transitionTimingFunction: { + drawer: 'cubic-bezier(0.25, 0.8, 0.25, 1)', + }, + + // @tailwindcss/typography + typography: ({ theme }) => ({ + DEFAULT: { + css: { + color: 'var(--fuse-text-default)', + '[class~="lead"]': { + color: 'var(--fuse-text-secondary)', + }, + a: { + color: 'var(--fuse-primary-500)', + }, + strong: { + color: 'var(--fuse-text-default)', + }, + 'ol > li::before': { + color: 'var(--fuse-text-secondary)', + }, + 'ul > li::before': { + backgroundColor: 'var(--fuse-text-hint)', + }, + hr: { + borderColor: 'var(--fuse-border)', + }, + blockquote: { + color: 'var(--fuse-text-default)', + borderLeftColor: 'var(--fuse-border)', + }, + h1: { + color: 'var(--fuse-text-default)', + }, + h2: { + color: 'var(--fuse-text-default)', + }, + h3: { + color: 'var(--fuse-text-default)', + }, + h4: { + color: 'var(--fuse-text-default)', + }, + 'figure figcaption': { + color: 'var(--fuse-text-secondary)', + }, + code: { + color: 'var(--fuse-text-default)', + fontWeight: '500', + }, + 'a code': { + color: 'var(--fuse-primary)', + }, + pre: { + color: theme('colors.white'), + backgroundColor: theme('colors.gray.800'), + }, + thead: { + color: 'var(--fuse-text-default)', + borderBottomColor: 'var(--fuse-border)', + }, + 'tbody tr': { + borderBottomColor: 'var(--fuse-border)', + }, + 'ol[type="A" s]': false, + 'ol[type="a" s]': false, + 'ol[type="I" s]': false, + 'ol[type="i" s]': false, + }, + }, + sm: { + css: { + code: { + fontSize: '1em', + }, + pre: { + fontSize: '1em', + }, + table: { + fontSize: '1em', + }, + }, + }, + }), + }, + }, + corePlugins: { + appearance: false, + container: false, + float: false, + clear: false, + placeholderColor: false, + placeholderOpacity: false, + verticalAlign: false, + }, + plugins: [ + // Fuse - Tailwind plugins + require( + path.resolve(__dirname, 'src/@fuse/tailwind/plugins/utilities') + ), + require( + path.resolve(__dirname, 'src/@fuse/tailwind/plugins/icon-size') + ), + require(path.resolve(__dirname, 'src/@fuse/tailwind/plugins/theming'))({ + themes, + }), + + // Other third party and/or custom plugins + require('@tailwindcss/typography')({ modifiers: ['sm', 'lg'] }), + ], +}; + +module.exports = config; diff --git a/frontend/transloco.config.js b/frontend/transloco.config.js new file mode 100644 index 00000000..c2f49519 --- /dev/null +++ b/frontend/transloco.config.js @@ -0,0 +1,3 @@ +module.exports = { + rootTranslationsPath: 'src/assets/i18n/', +}; diff --git a/frontend/tsconfig.app.json b/frontend/tsconfig.app.json index ff396d4c..3b3c1940 100644 --- a/frontend/tsconfig.app.json +++ b/frontend/tsconfig.app.json @@ -1,10 +1,13 @@ /* To learn more about this file see: https://angular.io/config/tsconfig. */ { - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "./out-tsc/app", - "types": [] - }, - "files": ["src/main.ts", "src/polyfills.ts"], - "include": ["src/**/*.d.ts"] + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/app", + "types": [], + "paths": { + "@env/*": ["./src/environments/*"] + } + }, + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"] } diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index ffe6afa3..5f232778 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -1,38 +1,21 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ { - "compileOnSave": false, - "compilerOptions": { - "outDir": "./dist/out-tsc", - "forceConsistentCasingInFileNames": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "sourceMap": true, - "declaration": false, - "module": "es2020", - "moduleResolution": "node", - "downlevelIteration": true, - "experimentalDecorators": true, - "importHelpers": true, - "strict": true, - "suppressImplicitAnyIndexErrors": true, - "target": "es2021", - "typeRoots": ["node_modules/@types"], - "lib": ["es2021", "dom"], - "baseUrl": "./", - "paths": { - "@app/*": ["src/app/*"], - "@shared": ["src/app/@shared"], - "@shared/*": ["src/app/@shared/*"], - "@env/*": ["src/environments/*"] + "compileOnSave": false, + "compilerOptions": { + "baseUrl": "./src", + "outDir": "./dist/out-tsc", + "esModuleInterop": true, + "sourceMap": true, + "declaration": false, + "experimentalDecorators": true, + "moduleResolution": "bundler", + "importHelpers": true, + "target": "ES2022", + "module": "ES2022", + "useDefineForClassFields": false, + "lib": ["ES2022", "dom"] + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false } - }, - "angularCompilerOptions": { - "enableI18nLegacyMessageIdFormat": false, - "fullTemplateTypeCheck": true, - "strictInjectionParameters": true, - "strictInputAccessModifiers": true, - "strictTemplates": true, - "preserveWhitespaces": true - } } diff --git a/frontend/tsconfig.spec.json b/frontend/tsconfig.spec.json index 872c9f91..272b3279 100644 --- a/frontend/tsconfig.spec.json +++ b/frontend/tsconfig.spec.json @@ -1,10 +1,9 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ { - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "./out-tsc/spec", - "allowJs": true, - "types": ["jest", "node"] - }, - "files": ["src/polyfills.ts"], - "include": ["src/**/*.spec.ts", "src/**/*.mock.ts", "src/**/*.d.ts"] + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/spec", + "types": ["jasmine"] + }, + "include": ["src/**/*.spec.ts", "src/**/*.d.ts"] } diff --git a/frontend/tslint.json b/frontend/tslint.json deleted file mode 100644 index 8bcda38d..00000000 --- a/frontend/tslint.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "extends": ["tslint:recommended", "tslint-config-prettier"], - "rulesDirectory": ["codelyzer"], - "rules": { - "array-type": false, - "arrow-parens": false, - "deprecation": { - "severity": "warning" - }, - "import-blacklist": [true, "rxjs/Rx"], - "max-line-length": [true, 120], - "member-access": false, - "member-ordering": [ - true, - { - "order": [ - "public-static-field", - "protected-static-field", - "private-static-field", - "public-instance-field", - "protected-instance-field", - "private-instance-field", - "public-static-method", - "protected-static-method", - "private-static-method", - "constructor", - "public-instance-method", - "protected-instance-method", - "private-instance-method" - ] - } - ], - "interface-name": false, - "max-classes-per-file": false, - "no-consecutive-blank-lines": false, - "no-console": [true, "debug", "time", "timeEnd", "trace"], - "no-duplicate-variable": [true, "check-parameters"], - "no-empty": false, - "no-inferrable-types": [true, "ignore-params"], - "no-non-null-assertion": true, - "no-redundant-jsdoc": true, - "no-switch-case-fall-through": true, - "no-unnecessary-initializer": true, - "object-literal-sort-keys": false, - "quotemark": [true, "single"], - "typedef": [true, "parameter", "property-declaration"], - "variable-name": false, - "no-var-requires": false, - "object-literal-key-quotes": false, - "ordered-imports": false, - "trailing-comma": false, - "no-conflicting-lifecycle": true, - "no-output-native": true, - "directive-selector": [true, "attribute", "app", "camelCase"], - "component-selector": [true, "element", "page", "app", "kebab-case"], - "template-banana-in-box": true, - "template-no-negated-async": true, - "no-output-on-prefix": true, - "no-inputs-metadata-property": true, - "no-outputs-metadata-property": true, - "no-host-metadata-property": true, - "no-input-rename": true, - "no-output-rename": true, - "use-lifecycle-interface": true, - "use-pipe-transform-interface": true, - "component-class-suffix": true, - "contextual-lifecycle": true, - "directive-class-suffix": true - } -} diff --git a/projectInfo.json b/projectInfo.json index fffabf6e..f5582bc5 100644 --- a/projectInfo.json +++ b/projectInfo.json @@ -1,13 +1,12 @@ [ { - "asd":" && cd frontend && npm run build && cd frontend && npm run lint", "baseDir": "./", "language": "typescript", "initialise": "npm install", "compile": "npm run build && cd frontend && npm run build", "format": "", "staticAnalysis": "npm run lint ", - "test": "npm run test", + "test": "npm run test && cd frontend && npm run test", "languageTools": "typescript", "devBranch": "main" } diff --git a/src/agent/humanInTheLoop.ts b/src/agent/humanInTheLoop.ts index 9524a9eb..cbac51e0 100644 --- a/src/agent/humanInTheLoop.ts +++ b/src/agent/humanInTheLoop.ts @@ -7,6 +7,7 @@ import { logger } from '#o11y/logger'; */ import { startSpan, withSpan } from '#o11y/trace'; import { sleep } from '#utils/async-utils'; +import { beep } from '#utils/beep'; export async function waitForConsoleInput(humanInLoopReason: string) { await withSpan('consoleHumanInLoop', async () => { @@ -15,13 +16,7 @@ export async function waitForConsoleInput(humanInLoopReason: string) { // await appContext().agentStateService.updateState(agentContextStorage.getStore(), 'humanInLoop_agent'); // Beep beep! - const delayMs = 100; - const beeps = 3; - - for (let i = 0; i < beeps; i++) { - process.stdout.write('\u0007'); - await sleep(delayMs); - } + await beep(); const rl = readline.createInterface({ input: process.stdin, diff --git a/src/chat/chatTypes.ts b/src/chat/chatTypes.ts index 77f13482..74e85989 100644 --- a/src/chat/chatTypes.ts +++ b/src/chat/chatTypes.ts @@ -27,4 +27,5 @@ export interface ChatService { listChats(startAfter?: string, limit?: number): Promise; loadChat(chatId: string): Promise; saveChat(chat: Chat): Promise; + deleteChat(chatId: string): Promise; } diff --git a/src/llm/llm.ts b/src/llm/llm.ts index 90f1675c..c59990fd 100644 --- a/src/llm/llm.ts +++ b/src/llm/llm.ts @@ -38,6 +38,8 @@ export interface LlmMessage { llmId?: string; /** Set the cache_control flag with Claude models */ cache?: 'ephemeral'; + /** Time the message was sent */ + time?: number; } export function system(text: string, cache = false): LlmMessage { diff --git a/src/modules/firestore/firestoreChatService.ts b/src/modules/firestore/firestoreChatService.ts index 2e3719e7..be1cf97a 100644 --- a/src/modules/firestore/firestoreChatService.ts +++ b/src/modules/firestore/firestoreChatService.ts @@ -114,4 +114,30 @@ export class FirestoreChatService implements ChatService { throw error; } } + + @span() + async deleteChat(chatId: string): Promise { + try { + const userId = currentUser().id; + const docRef = this.db.doc(`Chats/${chatId}`); + const docSnap = await docRef.get(); + + if (!docSnap.exists) { + logger.warn(`Chat with id ${chatId} not found`); + throw new Error(`Chat with id ${chatId} not found`); + } + + const chatData = docSnap.data(); + if (chatData.userId !== userId) { + logger.warn(`User ${userId} is not authorized to delete chat ${chatId}`); + throw new Error('Not authorized to delete this chat'); + } + + await docRef.delete(); + logger.info(`Chat ${chatId} deleted successfully`); + } catch (error) { + logger.error(error, `Error deleting chat ${chatId}`); + throw error; + } + } } diff --git a/src/routes/chat/chat-routes.ts b/src/routes/chat/chat-routes.ts index 1076cf7c..c0ba2a0a 100644 --- a/src/routes/chat/chat-routes.ts +++ b/src/routes/chat/chat-routes.ts @@ -27,6 +27,57 @@ export async function chatRoutes(fastify: AppFastifyInstance) { send(reply, 200, chat); }, ); + fastify.post( + `${basePath}/chat/new`, + { + schema: { + body: Type.Object({ + text: Type.String(), + llmId: Type.String(), + cache: Type.Optional(Type.Boolean()), + temperature: Type.Optional(Type.Number()), + }), + }, + }, + async (req, reply) => { + const { text, llmId, cache } = req.body; + + let chat: Chat = { + id: randomUUID(), + messages: [], + title: '', + updatedAt: Date.now(), + userId: currentUser().id, + visibility: 'private', + parentId: undefined, + rootId: undefined, + }; + + let llm: LLM = getLLM(Claude3_5_Sonnet_Vertex().getId()); + try { + llm = getLLM(llmId); + } catch (e) { + logger.error(`No LLM for ${llmId}`); + } + if (!llm.isConfigured()) return sendBadRequest(reply, `LLM ${llm.getId()} is not configured`); + + const titlePromise: Promise | undefined = llm.generateText( + text, + 'The following message is the first message in a new chat conversation. Your task is to create a short title for the conversation. Respond only with the title, nothing else', + ); + + chat.messages.push({ role: 'user', text: text, time: Date.now() }); //, cache: cache ? 'ephemeral' : undefined // remove any previous cache marker + + const generatedMessage = await llm.generateTextFromMessages(chat.messages); + chat.messages.push({ role: 'assistant', text: generatedMessage, llmId: llmId, time: Date.now() }); + + if (titlePromise) chat.title = await titlePromise; + + chat = await fastify.chatService.saveChat(chat); + + send(reply, 200, chat); + }, + ); fastify.post( `${basePath}/chat/:chatId/send`, { @@ -46,19 +97,7 @@ export async function chatRoutes(fastify: AppFastifyInstance) { const { chatId } = req.params; // Extract 'chatId' from path parameters const { text, llmId, cache } = req.body; - const isNew = chatId === 'new'; - const chat: Chat = isNew - ? { - id: randomUUID(), - messages: [], - title: '', - updatedAt: Date.now(), - userId: currentUser().id, - visibility: 'private', - parentId: undefined, - rootId: undefined, - } - : await fastify.chatService.loadChat(chatId); + const chat: Chat = await fastify.chatService.loadChat(chatId); let llm: LLM = getLLM(Claude3_5_Sonnet_Vertex().getId()); try { @@ -68,19 +107,10 @@ export async function chatRoutes(fastify: AppFastifyInstance) { } if (!llm.isConfigured()) return sendBadRequest(reply, `LLM ${llm.getId()} is not configured`); - const titlePromise: Promise | undefined = isNew - ? llm.generateText( - text, - 'The following message is the first message in a new chat conversation. Your task is to create a short title for the conversation. Respond only with the title, nothing else', - ) - : undefined; - - chat.messages.push({ role: 'user', text: text }); //, cache: cache ? 'ephemeral' : undefined // remove any previous cache marker + chat.messages.push({ role: 'user', text: text, time: Date.now() }); //, cache: cache ? 'ephemeral' : undefined // remove any previous cache marker const generatedMessage = await llm.generateTextFromMessages(chat.messages); - chat.messages.push({ role: 'assistant', text: generatedMessage }); - - if (titlePromise) chat.title = await titlePromise; + chat.messages.push({ role: 'assistant', text: generatedMessage, llmId, time: Date.now() }); await fastify.chatService.saveChat(chat); @@ -102,4 +132,29 @@ export async function chatRoutes(fastify: AppFastifyInstance) { send(reply, 200, chats); }, ); + fastify.delete( + `${basePath}/chat/:chatId`, + { + schema: { + params: Type.Object({ + chatId: Type.String(), + }), + }, + }, + async (req, reply) => { + const { chatId } = req.params; + const userId = currentUser().id; + try { + const chat = await fastify.chatService.loadChat(chatId); + if (chat.userId !== userId) { + return sendBadRequest(reply, 'Unauthorized to delete this chat'); + } + await fastify.chatService.deleteChat(chatId); + send(reply, 200, { success: true }); + } catch (error) { + logger.error(`Failed to delete chat ${chatId}:`, error); + send(reply, 500, { error: 'Failed to delete chat' }); + } + }, + ); } diff --git a/src/routes/code/code-routes.ts b/src/routes/code/code-routes.ts index f829e4dc..bb4705de 100644 --- a/src/routes/code/code-routes.ts +++ b/src/routes/code/code-routes.ts @@ -16,6 +16,7 @@ import { sophiaDirName, systemDir } from '../../appVars'; function findRepositories(dir: string): string[] { const repos: string[] = []; + if (!fs.existsSync(dir)) return []; const items = fs.readdirSync(dir, { withFileTypes: true }); for (const item of items) { diff --git a/src/utils/beep.ts b/src/utils/beep.ts new file mode 100644 index 00000000..dc4f3acf --- /dev/null +++ b/src/utils/beep.ts @@ -0,0 +1,11 @@ +import { sleep } from '#utils/async-utils'; + +export async function beep() { + const delayMs = 100; + const beeps = 3; + + for (let i = 0; i < beeps; i++) { + process.stdout.write('\u0007'); + await sleep(delayMs); + } +}