diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..0e796c3 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +node_modules +dist +build \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..c5ad0df --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,113 @@ +{ + "root": true, + "ignorePatterns": ["**/*"], + "plugins": ["@nx"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": { + "@nx/enforce-module-boundaries": [ + "error", + { + "enforceBuildableLibDependency": true, + "allow": [], + "depConstraints": [ + { + "sourceTag": "*", + "onlyDependOnLibsWithTags": ["*"] + } + ] + } + ] + } + }, + { + "files": ["*.ts", "*.tsx"], + "extends": ["plugin:@nx/typescript", "eslint:recommended", "plugin:@typescript-eslint/recommended"], + "plugins": [ + "@typescript-eslint/eslint-plugin", + "unused-imports", + "import", + "max-params-no-constructor", + "simple-import-sort" + ], + "rules": { + "arrow-parens": "off", + "complexity": "error", + "interface-name": "off", + "max-depth": "error", + "max-lines": [ + "error", + { + "max": 400 + } + ], + "max-lines-per-function": [ + "error", + { + "max": 50 + } + ], + "max-nested-callbacks": [ + "error", + { + "max": 3 + } + ], + "max-params": ["error", 10], + "max-params-no-constructor/max-params-no-constructor": ["error", 4], + "member-access": "off", + "no-console": [ + "error", + { + "allow": ["error", "warn", "info", "table"] + } + ], + "no-duplicate-imports": "error", + "no-empty": "error", + "no-fallthrough": "error", + "no-param-reassign": "error", + "no-unreachable": "error", + "no-unreachable-loop": "error", + "no-var": "error", + "object-literal-sort-keys": "off", + "prefer-const": "error", + "quotes": [ + "warn", + "single", + { + "avoidEscape": true + } + ], + "simple-import-sort/imports": [ + "error", + { + "groups": [ + // Side effects. + ["^\\u0000"], + // 3rd party. + ["^@?\\w"], + // Anything not fitting group above. + ["^"], + // Relative imports. + ["^\\."] + ] + } + ], + "simple-import-sort/exports": "error" + } + }, + { + "files": ["*.js", "*.jsx"], + "extends": ["plugin:@nx/javascript"], + "rules": {} + }, + { + "files": ["*.spec.ts", "*.spec.tsx", "*.spec.js", "*.spec.jsx"], + "env": { + "jest": true + }, + "rules": {} + } + ] +} diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..fbffc68 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,29 @@ +# Description + + + +## Type of change + +Please delete options that are not relevant. + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] Dependencies update +- [ ] Refactor (a code change that neither fixes a bug nor adds a feature) +- [ ] This change requires a documentation update + +## Checklist: + +- [ ] My code follows the style guidelines of this project +- [ ] I have performed a self-review of my own code +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] I have made corresponding changes to the documentation +- [ ] My changes generate no new warnings +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] New and existing unit tests pass locally with my changes +- [ ] Any dependent changes have been merged and published in downstream modules diff --git a/.github/workflows/node.yml b/.github/workflows/node.yml new file mode 100644 index 0000000..6faffd0 --- /dev/null +++ b/.github/workflows/node.yml @@ -0,0 +1,139 @@ +name: NestJS Tools CI + +on: + push: + paths-ignore: + - 'README.md' + - '**/package-lock.json' + branches: + - main + pull_request: + types: + - opened + - reopened + - synchronize + - ready_for_review + paths-ignore: + - 'README.md' + - '**/package-lock.json' + branches: + - main + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + NX_CLOUD_DISTRIBUTED_EXECUTION: false + NX_DISTRIBUTED_TASK_EXECUTION: false + CI: true + +jobs: + setup-and-test: + runs-on: ubuntu-latest + if: ${{ github.event_name == 'push' || !github.event.pull_request.draft }} + timeout-minutes: 10 + + strategy: + matrix: + node-version: [18.x, 20.x] + + services: + rabbitmq: + image: rabbitmq:3.9-management-alpine + options: >- + --health-cmd "rabbitmq-diagnostics status" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5672:5672 + + steps: + - name: Check out repository code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ github.head_ref }} + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: 'npm' + + - name: Derive appropriate SHAs for base and head for `nx affected` commands + id: set-sha + uses: nrwl/nx-set-shas@v4 + + - name: Install dependencies + run: npm ci + + - uses: 8BitJonny/gh-get-current-pr@3.0.0 + id: current-pr + + - if: steps.current-pr.outputs.number != 'null' && github.ref_name != 'main' + # This line is needed for nx affected to work when CI is running on a PR + run: git branch --track main origin/main + + # Boot package has issues with @asyncapi monorepo + # - name: Scan dependencies with Audit CI + # run: npm run scan:deps + + - run: npx nx format:check + + - name: Run checks + env: + CI: true + S3_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }} + S3_BUCKET: ${{ secrets.S3_BUCKET }} + S3_REGION: ${{ secrets.S3_REGION }} + S3_ENDPOINT: ${{ secrets.S3_ENDPOINT }} + S3_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }} + run: npx nx affected -t lint,test,build --parallel=3 + + - name: Upload coverage + uses: actions/upload-artifact@v4 + with: + name: coverage-${{ matrix.node-version }} + path: ./coverage + retention-days: 2 + + scan: + needs: setup-and-test + runs-on: ubuntu-latest + timeout-minutes: 10 + + strategy: + matrix: + node-version: [18.x] + + steps: + - name: Check out repository code + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: Get current version + id: package-version + uses: martinbeentjes/npm-get-version-action@main + + - name: Retrieve coverage + uses: actions/download-artifact@v4 + with: + name: coverage-${{ matrix.node-version }} + path: ./coverage + + - name: SonarCloud Scan + uses: sonarsource/sonarcloud-github-action@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + with: + args: > + -Dsonar.projectVersion=${{ steps.package-version.outputs.current-version }} diff --git a/.gitignore b/.gitignore index ef9dcfb..3fa5166 100644 --- a/.gitignore +++ b/.gitignore @@ -1,41 +1,116 @@ -# See http://help.github.com/ignore-files/ for more about ignoring files. +.cache +**/.DS_Store -# compiled output +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt dist -tmp -/out-tsc - -# dependencies -node_modules - -# IDEs and editors -/.idea -.project -.classpath -.c9/ -*.launch -.settings/ -*.sublime-workspace - -# IDE - VSCode -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json - -# misc -/.sass-cache -/connect.lock -/coverage -/libpeerconnection.log -npm-debug.log -yarn-error.log -testem.log -/typings - -# System Files -.DS_Store -Thumbs.db +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and *not* Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Sonar scanner +.scannerwork + +junit.xml + +#Nx +.tmp/ .nx/cache diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100755 index 0000000..5a85000 --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +npx --no -- commitlint --edit $1 diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..36af219 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +npx lint-staged diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..fa3a9d7 --- /dev/null +++ b/.npmignore @@ -0,0 +1,16 @@ +src +test +tsconfig.json +tsconfig.module.json +.eslintrc.js +.prettierrc.js +.github +.prettierignore +.vscode +.env +build/docs +**/*.spec.* +coverage +.scannerwork +.nyc_output +*.log diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..d155fdb --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +# Add files here to ignore them from prettier formatting +/dist +/coverage +/.nx/cache \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..b25b3e3 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,11 @@ +{ + "singleQuote": true, + "arrowParens": "always", + "bracketSpacing": true, + "endOfLine": "auto", + "useTabs": false, + "semi": true, + "trailingComma": "all", + "tabWidth": 2, + "printWidth": 120 +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json index bf14b26..0d71aba 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,6 +1,3 @@ { - "recommendations": [ - - "nrwl.angular-console" - ] + "recommendations": ["nrwl.angular-console", "esbenp.prettier-vscode", "firsttris.vscode-jest-runner"] } diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index 6af7295..abfae3b 100644 --- a/README.md +++ b/README.md @@ -1,76 +1,31 @@ -# NestjsTools +

+ NestOry Logo +

- +# NestJS Tools -โœจ **This workspace has been generated by [Nx, Smart Monorepos ยท Fast CI.](https://nx.dev)** โœจ +[![License: Apache 2.0](https://img.shields.io/badge/License-Apache-yellow.svg)](https://opensource.org/license/apache-2-0) +[![CI](https://github.com/getlarge/nestjs-tools/actions/workflows/node.yml/badge.svg)](https://github.com/getlarge/nestjs-tools/actions/workflows/node.yml) +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=getlarge_nestjs-tools&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=getlarge_nestjs-tools) +[![code style: Prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier) -## Integrate with editors +This repository contains several helpful packages for NestJS that I have developed for NestJS applications running in production. -Enhance your Nx experience by installing [Nx Console](https://nx.dev/nx-console) for your favorite editor. Nx Console -provides an interactive UI to view your projects, run tasks, generate code, and more! Available for VSCode, IntelliJ and -comes with a LSP for Vim users. +## List of packages -## Nx plugins and code generators +| Package | Description | Version | +| --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| [AMQP-Transport](./packages/amqp-transport/README.md) | A NestJS microservice adapter around [AMQPlib](https://amqp-node.github.io/amqplib/) supporting exchanges | [![npm](https://img.shields.io/npm/v/@getlarge/nestjs-tools-amqp-transport.svg?style=flat)](https://npmjs.org/package/@getlarge/nestjs-tools-amqp-transport) | +| [Async-Local-Storage](./packages/async-local-storage/README.md) | A NestJS module to provide async local storage for your application | [![npm](https://img.shields.io/npm/v/@getlarge/nestjs-tools-async-local-storage?style=flat)](https://npmjs.org/package/@getlarge/nestjs-tools-async-local-storage) | +| [File-Storage](./packages/file-storage/README.md) | A NestJS module supporting FS and S3 strategies | [![npm](https://img.shields.io/npm/v/@getlarge/nestjs-tools-file-storage?style=flat)](https://npmjs.org/package/@getlarge/nestjs-tools-file-storage) | +| [Lock](./packages/lock/README.md) | A NestJS module to provide a distributed lock for your application | [![npm](https://img.shields.io/npm/v/@getlarge/nestjs-tools-lock?style=flat)](https://npmjs.org/package/@getlarge/nestjs-tools-lock) | -Add Nx plugins to leverage their code generators and automated, inferred tasks. +## Installation and usage -``` -# Add plugin -npx nx add @nx/react +Check the README of each package for more details. -# Use code generator -npx nx generate @nx/react:app demo +## Examples -# Run development server -npx nx serve demo +Check out the following projects for examples of using these packages: -# View project details -npx nx show project demo --web -``` - -Run `npx nx list` to get a list of available plugins and whether they have generators. Then run `npx nx list ` to see what generators are available. - -Learn more about [code generators](https://nx.dev/features/generate-code) and [inferred tasks](https://nx.dev/concepts/inferred-tasks) in the docs. - -## Running tasks - -To execute tasks with Nx use the following syntax: - -``` -npx nx <...options> -``` - -You can also run multiple targets: - -``` -npx nx run-many -t -``` - -..or add `-p` to filter specific projects - -``` -npx nx run-many -t -p -``` - -Targets can be defined in the `package.json` or `projects.json`. Learn more [in the docs](https://nx.dev/features/run-tasks). - -## Set up CI! - -Nx comes with local caching already built-in (check your `nx.json`). On CI you might want to go a step further. - -- [Set up remote caching](https://nx.dev/features/share-your-cache) -- [Set up task distribution across multiple machines](https://nx.dev/nx-cloud/features/distribute-task-execution) -- [Learn more how to setup CI](https://nx.dev/recipes/ci) - -## Explore the project graph - -Run `npx nx graph` to show the graph of the workspace. -It will show tasks that you can run with Nx. - -- [Learn more about Exploring the Project Graph](https://nx.dev/core-features/explore-graph) - -## Connect with us! - -- [Join the community](https://nx.dev/community) -- [Subscribe to the Nx Youtube Channel](https://www.youtube.com/@nxdevtools) -- [Follow us on Twitter](https://twitter.com/nxdevtools) +- the [ticketing repository](https://github.com/getlarge/ticketing) is a real-world example of AMQP-Transport, File-Storage, Lock, diff --git a/audit-ci.json b/audit-ci.json new file mode 100644 index 0000000..618f24e --- /dev/null +++ b/audit-ci.json @@ -0,0 +1,6 @@ +{ + "high": true, + "package-manager": "auto", + "report-type": "summary", + "skip-dev": true +} diff --git a/commitlint.config.js b/commitlint.config.js new file mode 100644 index 0000000..bdf6d88 --- /dev/null +++ b/commitlint.config.js @@ -0,0 +1,104 @@ +const { getProjects } = require('@nx/devkit'); +const { FsTree } = require('nx/src/generators/tree'); + +/* + * Type-Enums and their documentation as reusable const. + */ +const typeEnumDescription = { + feat: { + description: 'Adding new functionality', + title: 'Feature', + emoji: '๐Ÿฃ', + }, + docs: { + description: 'Documentation only changes', + title: 'Documentation', + emoji: '๐Ÿ“œ', + }, + format: { + description: + 'Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)', + title: 'Formatting', + emoji: '๐Ÿ’Ž', + }, + refactor: { + description: 'A code change that neither fixes a bug nor adds a feature', + title: 'Code Refactoring', + emoji: 'โ™ป', + }, + perf: { + description: 'A code change that improves performance', + title: 'Performance Improvements', + emoji: '๐Ÿš€', + }, + deprecate: { + description: 'A code change that deprecates APIs or is related to their deprecation', + title: 'Code Deprecations', + emoji: '๐Ÿ•ธ', + }, + test: { + description: 'Adding missing tests or correcting existing tests', + title: 'Tests', + emoji: '๐Ÿ›‚', + }, + build: { + description: 'Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)', + title: 'Builds', + emoji: '๐Ÿ“ฆ', + }, + ci: { + description: + 'Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)', + title: 'Continuous Integrations', + emoji: '๐Ÿญ', + }, + chore: { + description: "Other changes that don't modify src or test files", + title: 'Chores', + emoji: 'โš™', + }, + revert: { + description: 'Reverts a previous commit', + title: 'Reverts', + emoji: '๐Ÿ—‘', + }, + fix: { + description: 'A code change that fixes an error or bug', + title: 'Fix', + emoji: '๐Ÿ’‰', + }, +}; + +/* + * Scope-Enums defined from constants and Nx projects. + */ +const baseScopes = ['release']; + +const scopeEnum = () => { + const tree = new FsTree('.'); + const projects = getProjects(tree); + return [...baseScopes, ...projects.keys()]; +}; + +const Configuration = { + /* + * Resolve and load @commitlint/config-conventional from node_modules. + * Referenced packages must be installed + */ + extends: ['@commitlint/config-conventional'], + /* + * Override rules from @commitlint/config-conventional + */ + rules: { + /* + * Customized types matching CU folders + */ + 'type-enum': [2, 'always', Object.keys(typeEnumDescription)], + /* + * Scope enums derived from projects registered in `workspace.json` + */ + 'scope-enum': [2, 'always', scopeEnum()], + }, +}; + +module.exports = Configuration; diff --git a/coverage-transform.js b/coverage-transform.js new file mode 100644 index 0000000..0732756 --- /dev/null +++ b/coverage-transform.js @@ -0,0 +1,40 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +const path = require('path'); +const { readFileSync, writeFileSync } = require('fs'); + +function fixLcovFilepaths() { + const lcovFile = path.resolve(__dirname, './coverage/lcov.info'); + const rawFile = readFileSync(lcovFile, 'utf8'); + const rebuiltPaths = rawFile + .split('\n') + .map((singleLine) => { + if (singleLine.startsWith('SF:')) { + return singleLine.replace('SF:../', `SF:${__dirname}/packages/`); + } + return singleLine; + }) + .join('\n'); + writeFileSync(lcovFile, rebuiltPaths, 'utf8'); + return rebuiltPaths; +} + +function fixSonarReportFilePaths() { + const sonarReportFile = path.resolve(__dirname, './coverage/sonar-report.xml'); + const rawFile = readFileSync(sonarReportFile, 'utf8'); + const rebuiltPaths = rawFile + .split('\n') + .map((singleLine) => { + if (singleLine.startsWith(' { + fixLcovFilepaths(); + fixSonarReportFilePaths(); +})(); diff --git a/jest.config.ts b/jest.config.ts new file mode 100644 index 0000000..6b3f2d6 --- /dev/null +++ b/jest.config.ts @@ -0,0 +1,5 @@ +import { getJestProjectsAsync } from '@nx/jest'; + +export default async () => ({ + projects: await getJestProjectsAsync(), +}); diff --git a/jest.preset.js b/jest.preset.js new file mode 100644 index 0000000..971285c --- /dev/null +++ b/jest.preset.js @@ -0,0 +1,3 @@ +const nxPreset = require('@nx/jest/preset').default; + +module.exports = { ...nxPreset, coverageReporters: ['json', 'lcov'] }; diff --git a/lerna.json b/lerna.json new file mode 100644 index 0000000..50ca1e7 --- /dev/null +++ b/lerna.json @@ -0,0 +1,13 @@ +{ + "packages": ["packages/*"], + "npmClient": "npm", + "version": "independent", + "command": { + "publish": { + "ignoreChanges": ["**/package-lock.json", "*.md", "**/*.spec.ts", "**/fixtures/*"], + "conventionalCommits": true, + "message": "chore(release): publish" + } + }, + "$schema": "node_modules/lerna/schemas/lerna-schema.json" +} diff --git a/merge-coverage.js b/merge-coverage.js new file mode 100644 index 0000000..cdd10bd --- /dev/null +++ b/merge-coverage.js @@ -0,0 +1,62 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +const { existsSync, readFileSync, readdirSync } = require('fs'); +const { createCoverageMap } = require('istanbul-lib-coverage'); +const { createContext } = require('istanbul-lib-report'); +const { create: createReporter } = require('istanbul-reports'); +const path = require('path'); +const yargs = require('yargs'); +const { name } = require('./package.json'); + +const COVERAGE_FOLDER = 'coverage'; + +async function main() { + const argv = yargs.options({ + report: { + type: 'array', + desc: 'Path to json coverage report file(s)', + default: readdirSync(path.resolve('./packages'), { withFileTypes: true }) + .filter((dirent) => dirent.isDirectory()) + .map((dirent) => path.resolve('./packages', dirent.name, `${COVERAGE_FOLDER}/coverage-final.json`)), + }, + reporters: { + type: 'array', + default: ['json', 'lcov', 'text'], + }, + }).argv; + + const { report: reportFiles, reporters } = argv; + const coverageMap = createCoverageMap({}); + reportFiles.forEach((coveragePath) => { + if (!existsSync(coveragePath)) { + return; + } + let coverage = JSON.parse(readFileSync(coveragePath, 'utf8')); + if (process.env.CI) { + // fix invalid file path in Github actions + coverage = Object.keys(coverage).reduce((acc, key) => { + const filePath = key.replace(`/home/runner/work/${name}/${name}/`, ''); + const newKey = filePath; + coverage[key].path = filePath; + return { ...acc, [newKey]: coverage[key] }; + }, {}); + } + coverageMap.merge(coverage); + }); + + const context = createContext({ + dir: COVERAGE_FOLDER, + coverageMap, + }); + + reporters.forEach((reporter) => { + const report = createReporter(reporter); + report.execute(context); + }); + // eslint-disable-next-line no-console + console.log(`Created a merged coverage report in ./${COVERAGE_FOLDER}`); +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/nx.json b/nx.json index 027b7d1..7d5f7a7 100644 --- a/nx.json +++ b/nx.json @@ -1,4 +1,79 @@ { + "pluginsConfig": { + "@nx/js": { + "analyzeSourceFiles": true + } + }, "extends": "nx/presets/npm.json", - "$schema": "./node_modules/nx/schemas/nx-schema.json" + "$schema": "./node_modules/nx/schemas/nx-schema.json", + "namedInputs": { + "default": ["{projectRoot}/**/*", "sharedGlobals"], + "sharedGlobals": [], + "production": [ + "default", + "!{projectRoot}/test/**", + "!{projectRoot}/**/*.{spec,test}.ts", + "!{projectRoot}/node_modules/**" + ] + }, + "release": { + "projects": ["packages/*"], + "projectsRelationship": "independent", + "changelog": { + "projectChangelogs": { + "createRelease": "github" + } + }, + "version": { + "conventionalCommits": true, + "generatorOptions": { + "skipLockFileUpdate": true + } + }, + "git": { + "commit": true, + "tag": true + } + }, + "targetDefaults": { + "@nx/js:tsc": { + "cache": true, + "dependsOn": ["^build"], + "inputs": ["production", "^production"] + }, + "test": { + "cache": true, + "options": { + "passWithNoTests": true, + "collectCoverage": true + }, + "configurations": { + "ci": { + "ci": true, + "collectCoverage": true + } + } + }, + "nx-release-publish": { + "options": { + "packageRoot": "dist/{projectRoot}", + "registry": "https://registry.npmjs.org/" + }, + "dependsOn": ["build"] + } + }, + "plugins": [ + { + "plugin": "@nx/eslint/plugin", + "options": { + "targetName": "lint" + } + }, + { + "plugin": "@nx/jest/plugin", + "options": { + "targetName": "test" + } + } + ] } diff --git a/package-lock.json b/package-lock.json index b2a8c92..b587195 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,26 +1,104 @@ { "name": "nestjs-tools", - "version": "0.0.0", + "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "nestjs-tools", - "version": "0.0.0", - "license": "MIT", + "version": "0.1.0", + "license": "Apache-2.0", "workspaces": [ - "packages/*" + "packages/**" ], + "dependencies": { + "@aws-sdk/client-s3": "^3.554.0", + "@aws-sdk/lib-storage": "^3.554.0", + "@nestjs/common": "^10.0.2", + "@nestjs/config": "^3.2.2", + "@nestjs/core": "^10.0.2", + "@nestjs/microservices": "^10.0.2", + "@nestjs/platform-express": "^10.0.2", + "amqp-connection-manager": "^4.1.14", + "amqplib": "^0.10.4", + "ioredis": "^5.3.2", + "redlock": "^5.0.0-beta.2", + "reflect-metadata": "^0.1.14", + "rxjs": "^7.8.0", + "tslib": "^2.3.0", + "uuid": "^9.0.1" + }, "devDependencies": { + "@commitlint/cli": "^17.1.2", + "@commitlint/config-conventional": "^17.1.0", + "@nestjs/schematics": "^10.0.1", + "@nestjs/testing": "^10.0.2", + "@nx/eslint": "18.2.4", + "@nx/eslint-plugin": "18.2.4", + "@nx/jest": "18.2.4", "@nx/js": "18.2.4", - "nx": "18.2.4" + "@nx/nest": "^18.2.4", + "@swc-node/register": "~1.8.0", + "@swc/core": "~1.3.85", + "@swc/helpers": "~0.5.2", + "@types/amqplib": "^0.10.5", + "@types/express": "^4.17.21", + "@types/jest": "^29.4.0", + "@types/node": "^18.16.9", + "@types/supertest": "^6.0.2", + "@types/uuid": "^9.0.8", + "@typescript-eslint/eslint-plugin": "^7.3.0", + "@typescript-eslint/parser": "^7.3.0", + "audit-ci": "^6.3.0", + "dotenv": "^16.4.5", + "eslint": "~8.57.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-import": "^2.29.0", + "eslint-plugin-max-params-no-constructor": "^0.0.4", + "eslint-plugin-simple-import-sort": "^12.0.0", + "eslint-plugin-unused-imports": "^3.1.0", + "husky": "^9.0.11", + "ioredis-mock": "^8.9.0", + "jest": "^29.4.1", + "jest-environment-node": "^29.4.1", + "lint-staged": "^15.0.3", + "mqtt": "^5.5.2", + "nx": "18.2.4", + "prettier": "^2.6.2", + "supertest": "^6.3.4", + "ts-jest": "^29.1.0", + "ts-node": "10.9.1", + "typescript": "~5.4.2" + }, + "engines": { + "node": ">=14", + "npm": ">=7" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@acuminous/bitsyntax": { + "version": "0.1.2", + "license": "MIT", + "dependencies": { + "buffer-more-ints": "~1.0.0", + "debug": "^4.3.4", + "safe-buffer": "~5.1.2" + }, + "engines": { + "node": ">=0.8" } }, "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, + "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" @@ -29,1077 +107,1325 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/code-frame": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", - "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "node_modules/@angular-devkit/core": { + "version": "17.1.2", "dev": true, + "license": "MIT", "dependencies": { - "@babel/highlight": "^7.24.2", - "picocolors": "^1.0.0" + "ajv": "8.12.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.2.0", + "picomatch": "3.0.1", + "rxjs": "7.8.1", + "source-map": "0.7.4" }, "engines": { - "node": ">=6.9.0" + "node": "^18.13.0 || >=20.9.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/@babel/compat-data": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz", - "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==", + "node_modules/@angular-devkit/core/node_modules/jsonc-parser": { + "version": "3.2.0", "dev": true, - "engines": { - "node": ">=6.9.0" - } + "license": "MIT" }, - "node_modules/@babel/core": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz", - "integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==", + "node_modules/@angular-devkit/schematics": { + "version": "17.1.2", "dev": true, + "license": "MIT", "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.3", - "semver": "^6.3.1" + "@angular-devkit/core": "17.1.2", + "jsonc-parser": "3.2.0", + "magic-string": "0.30.5", + "ora": "5.4.1", + "rxjs": "7.8.1" }, "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" } }, - "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==", + "node_modules/@angular-devkit/schematics/node_modules/jsonc-parser": { + "version": "3.2.0", "dev": true, - "bin": { - "semver": "bin/semver.js" + "license": "MIT" + }, + "node_modules/@aws-crypto/crc32": { + "version": "3.0.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" } }, - "node_modules/@babel/generator": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", - "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", - "dev": true, + "node_modules/@aws-crypto/crc32/node_modules/tslib": { + "version": "1.14.1", + "license": "0BSD" + }, + "node_modules/@aws-crypto/crc32c": { + "version": "3.0.0", + "license": "Apache-2.0", "dependencies": { - "@babel/types": "^7.24.0", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" } }, - "node_modules/@babel/helper-annotate-as-pure": { - "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, + "node_modules/@aws-crypto/crc32c/node_modules/tslib": { + "version": "1.14.1", + "license": "0BSD" + }, + "node_modules/@aws-crypto/ie11-detection": { + "version": "3.0.0", + "license": "Apache-2.0", "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" + "tslib": "^1.11.1" } }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "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, + "node_modules/@aws-crypto/ie11-detection/node_modules/tslib": { + "version": "1.14.1", + "license": "0BSD" + }, + "node_modules/@aws-crypto/sha1-browser": { + "version": "3.0.0", + "license": "Apache-2.0", "dependencies": { - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" + "@aws-crypto/ie11-detection": "^3.0.0", + "@aws-crypto/supports-web-crypto": "^3.0.0", + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" } }, - "node_modules/@babel/helper-compilation-targets": { - "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, + "node_modules/@aws-crypto/sha1-browser/node_modules/tslib": { + "version": "1.14.1", + "license": "0BSD" + }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "3.0.0", + "license": "Apache-2.0", "dependencies": { - "@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" - }, - "engines": { - "node": ">=6.9.0" + "@aws-crypto/ie11-detection": "^3.0.0", + "@aws-crypto/sha256-js": "^3.0.0", + "@aws-crypto/supports-web-crypto": "^3.0.0", + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "node_modules/@aws-crypto/sha256-browser/node_modules/tslib": { + "version": "1.14.1", + "license": "0BSD" + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "3.0.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" } }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.4.tgz", - "integrity": "sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ==", - "dev": true, + "node_modules/@aws-crypto/sha256-js/node_modules/tslib": { + "version": "1.14.1", + "license": "0BSD" + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "3.0.0", + "license": "Apache-2.0", "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.23.0", - "@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.22.6", - "semver": "^6.3.1" + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/supports-web-crypto/node_modules/tslib": { + "version": "1.14.1", + "license": "0BSD" + }, + "node_modules/@aws-crypto/util": { + "version": "3.0.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/util/node_modules/tslib": { + "version": "1.14.1", + "license": "0BSD" + }, + "node_modules/@aws-sdk/client-s3": { + "version": "3.554.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha1-browser": "3.0.0", + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/client-sts": "3.554.0", + "@aws-sdk/core": "3.554.0", + "@aws-sdk/credential-provider-node": "3.554.0", + "@aws-sdk/middleware-bucket-endpoint": "3.535.0", + "@aws-sdk/middleware-expect-continue": "3.535.0", + "@aws-sdk/middleware-flexible-checksums": "3.535.0", + "@aws-sdk/middleware-host-header": "3.535.0", + "@aws-sdk/middleware-location-constraint": "3.535.0", + "@aws-sdk/middleware-logger": "3.535.0", + "@aws-sdk/middleware-recursion-detection": "3.535.0", + "@aws-sdk/middleware-sdk-s3": "3.552.0", + "@aws-sdk/middleware-signing": "3.552.0", + "@aws-sdk/middleware-ssec": "3.537.0", + "@aws-sdk/middleware-user-agent": "3.540.0", + "@aws-sdk/region-config-resolver": "3.535.0", + "@aws-sdk/signature-v4-multi-region": "3.552.0", + "@aws-sdk/types": "3.535.0", + "@aws-sdk/util-endpoints": "3.540.0", + "@aws-sdk/util-user-agent-browser": "3.535.0", + "@aws-sdk/util-user-agent-node": "3.535.0", + "@aws-sdk/xml-builder": "3.535.0", + "@smithy/config-resolver": "^2.2.0", + "@smithy/core": "^1.4.2", + "@smithy/eventstream-serde-browser": "^2.2.0", + "@smithy/eventstream-serde-config-resolver": "^2.2.0", + "@smithy/eventstream-serde-node": "^2.2.0", + "@smithy/fetch-http-handler": "^2.5.0", + "@smithy/hash-blob-browser": "^2.2.0", + "@smithy/hash-node": "^2.2.0", + "@smithy/hash-stream-node": "^2.2.0", + "@smithy/invalid-dependency": "^2.2.0", + "@smithy/md5-js": "^2.2.0", + "@smithy/middleware-content-length": "^2.2.0", + "@smithy/middleware-endpoint": "^2.5.1", + "@smithy/middleware-retry": "^2.3.1", + "@smithy/middleware-serde": "^2.3.0", + "@smithy/middleware-stack": "^2.2.0", + "@smithy/node-config-provider": "^2.3.0", + "@smithy/node-http-handler": "^2.5.0", + "@smithy/protocol-http": "^3.3.0", + "@smithy/smithy-client": "^2.5.1", + "@smithy/types": "^2.12.0", + "@smithy/url-parser": "^2.2.0", + "@smithy/util-base64": "^2.3.0", + "@smithy/util-body-length-browser": "^2.2.0", + "@smithy/util-body-length-node": "^2.3.0", + "@smithy/util-defaults-mode-browser": "^2.2.1", + "@smithy/util-defaults-mode-node": "^2.3.1", + "@smithy/util-endpoints": "^1.2.0", + "@smithy/util-retry": "^2.2.0", + "@smithy/util-stream": "^2.2.0", + "@smithy/util-utf8": "^2.3.0", + "@smithy/util-waiter": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sso": { + "version": "3.554.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/core": "3.554.0", + "@aws-sdk/middleware-host-header": "3.535.0", + "@aws-sdk/middleware-logger": "3.535.0", + "@aws-sdk/middleware-recursion-detection": "3.535.0", + "@aws-sdk/middleware-user-agent": "3.540.0", + "@aws-sdk/region-config-resolver": "3.535.0", + "@aws-sdk/types": "3.535.0", + "@aws-sdk/util-endpoints": "3.540.0", + "@aws-sdk/util-user-agent-browser": "3.535.0", + "@aws-sdk/util-user-agent-node": "3.535.0", + "@smithy/config-resolver": "^2.2.0", + "@smithy/core": "^1.4.2", + "@smithy/fetch-http-handler": "^2.5.0", + "@smithy/hash-node": "^2.2.0", + "@smithy/invalid-dependency": "^2.2.0", + "@smithy/middleware-content-length": "^2.2.0", + "@smithy/middleware-endpoint": "^2.5.1", + "@smithy/middleware-retry": "^2.3.1", + "@smithy/middleware-serde": "^2.3.0", + "@smithy/middleware-stack": "^2.2.0", + "@smithy/node-config-provider": "^2.3.0", + "@smithy/node-http-handler": "^2.5.0", + "@smithy/protocol-http": "^3.3.0", + "@smithy/smithy-client": "^2.5.1", + "@smithy/types": "^2.12.0", + "@smithy/url-parser": "^2.2.0", + "@smithy/util-base64": "^2.3.0", + "@smithy/util-body-length-browser": "^2.2.0", + "@smithy/util-body-length-node": "^2.3.0", + "@smithy/util-defaults-mode-browser": "^2.2.1", + "@smithy/util-defaults-mode-node": "^2.3.1", + "@smithy/util-endpoints": "^1.2.0", + "@smithy/util-middleware": "^2.2.0", + "@smithy/util-retry": "^2.2.0", + "@smithy/util-utf8": "^2.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc": { + "version": "3.554.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/client-sts": "3.554.0", + "@aws-sdk/core": "3.554.0", + "@aws-sdk/middleware-host-header": "3.535.0", + "@aws-sdk/middleware-logger": "3.535.0", + "@aws-sdk/middleware-recursion-detection": "3.535.0", + "@aws-sdk/middleware-user-agent": "3.540.0", + "@aws-sdk/region-config-resolver": "3.535.0", + "@aws-sdk/types": "3.535.0", + "@aws-sdk/util-endpoints": "3.540.0", + "@aws-sdk/util-user-agent-browser": "3.535.0", + "@aws-sdk/util-user-agent-node": "3.535.0", + "@smithy/config-resolver": "^2.2.0", + "@smithy/core": "^1.4.2", + "@smithy/fetch-http-handler": "^2.5.0", + "@smithy/hash-node": "^2.2.0", + "@smithy/invalid-dependency": "^2.2.0", + "@smithy/middleware-content-length": "^2.2.0", + "@smithy/middleware-endpoint": "^2.5.1", + "@smithy/middleware-retry": "^2.3.1", + "@smithy/middleware-serde": "^2.3.0", + "@smithy/middleware-stack": "^2.2.0", + "@smithy/node-config-provider": "^2.3.0", + "@smithy/node-http-handler": "^2.5.0", + "@smithy/protocol-http": "^3.3.0", + "@smithy/smithy-client": "^2.5.1", + "@smithy/types": "^2.12.0", + "@smithy/url-parser": "^2.2.0", + "@smithy/util-base64": "^2.3.0", + "@smithy/util-body-length-browser": "^2.2.0", + "@smithy/util-body-length-node": "^2.3.0", + "@smithy/util-defaults-mode-browser": "^2.2.1", + "@smithy/util-defaults-mode-node": "^2.3.1", + "@smithy/util-endpoints": "^1.2.0", + "@smithy/util-middleware": "^2.2.0", + "@smithy/util-retry": "^2.2.0", + "@smithy/util-utf8": "^2.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" }, - "engines": { - "node": ">=6.9.0" + "peerDependencies": { + "@aws-sdk/credential-provider-node": "^3.554.0" + } + }, + "node_modules/@aws-sdk/client-sts": { + "version": "3.554.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/core": "3.554.0", + "@aws-sdk/middleware-host-header": "3.535.0", + "@aws-sdk/middleware-logger": "3.535.0", + "@aws-sdk/middleware-recursion-detection": "3.535.0", + "@aws-sdk/middleware-user-agent": "3.540.0", + "@aws-sdk/region-config-resolver": "3.535.0", + "@aws-sdk/types": "3.535.0", + "@aws-sdk/util-endpoints": "3.540.0", + "@aws-sdk/util-user-agent-browser": "3.535.0", + "@aws-sdk/util-user-agent-node": "3.535.0", + "@smithy/config-resolver": "^2.2.0", + "@smithy/core": "^1.4.2", + "@smithy/fetch-http-handler": "^2.5.0", + "@smithy/hash-node": "^2.2.0", + "@smithy/invalid-dependency": "^2.2.0", + "@smithy/middleware-content-length": "^2.2.0", + "@smithy/middleware-endpoint": "^2.5.1", + "@smithy/middleware-retry": "^2.3.1", + "@smithy/middleware-serde": "^2.3.0", + "@smithy/middleware-stack": "^2.2.0", + "@smithy/node-config-provider": "^2.3.0", + "@smithy/node-http-handler": "^2.5.0", + "@smithy/protocol-http": "^3.3.0", + "@smithy/smithy-client": "^2.5.1", + "@smithy/types": "^2.12.0", + "@smithy/url-parser": "^2.2.0", + "@smithy/util-base64": "^2.3.0", + "@smithy/util-body-length-browser": "^2.2.0", + "@smithy/util-body-length-node": "^2.3.0", + "@smithy/util-defaults-mode-browser": "^2.2.1", + "@smithy/util-defaults-mode-node": "^2.3.1", + "@smithy/util-endpoints": "^1.2.0", + "@smithy/util-middleware": "^2.2.0", + "@smithy/util-retry": "^2.2.0", + "@smithy/util-utf8": "^2.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" }, "peerDependencies": { - "@babel/core": "^7.0.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", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "@aws-sdk/credential-provider-node": "^3.554.0" } }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "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, + "node_modules/@aws-sdk/core": { + "version": "3.554.0", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "regexpu-core": "^5.3.1", - "semver": "^6.3.1" + "@smithy/core": "^1.4.2", + "@smithy/protocol-http": "^3.3.0", + "@smithy/signature-v4": "^2.2.1", + "@smithy/smithy-client": "^2.5.1", + "@smithy/types": "^2.12.0", + "fast-xml-parser": "4.2.5", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=14.0.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", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.535.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.535.0", + "@smithy/property-provider": "^2.2.0", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.1.tgz", - "integrity": "sha512-o7SDgTJuvx5vLKD6SFvkydkSMBvahDKGiNJzG22IZYXhiqoe9efY7zocICBgzHV4IRg5wdgl2nEL/tulKIEIbA==", - "dev": true, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.552.0", + "license": "Apache-2.0", "dependencies": { - "@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" + "@aws-sdk/types": "3.535.0", + "@smithy/fetch-http-handler": "^2.5.0", + "@smithy/node-http-handler": "^2.5.0", + "@smithy/property-provider": "^2.2.0", + "@smithy/protocol-http": "^3.3.0", + "@smithy/smithy-client": "^2.5.1", + "@smithy/types": "^2.12.0", + "@smithy/util-stream": "^2.2.0", + "tslib": "^2.6.2" }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@babel/helper-environment-visitor": { - "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, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.554.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sts": "3.554.0", + "@aws-sdk/credential-provider-env": "3.535.0", + "@aws-sdk/credential-provider-process": "3.535.0", + "@aws-sdk/credential-provider-sso": "3.554.0", + "@aws-sdk/credential-provider-web-identity": "3.554.0", + "@aws-sdk/types": "3.535.0", + "@smithy/credential-provider-imds": "^2.3.0", + "@smithy/property-provider": "^2.2.0", + "@smithy/shared-ini-file-loader": "^2.4.0", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/helper-function-name": { - "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, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.554.0", + "license": "Apache-2.0", "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" + "@aws-sdk/credential-provider-env": "3.535.0", + "@aws-sdk/credential-provider-http": "3.552.0", + "@aws-sdk/credential-provider-ini": "3.554.0", + "@aws-sdk/credential-provider-process": "3.535.0", + "@aws-sdk/credential-provider-sso": "3.554.0", + "@aws-sdk/credential-provider-web-identity": "3.554.0", + "@aws-sdk/types": "3.535.0", + "@smithy/credential-provider-imds": "^2.3.0", + "@smithy/property-provider": "^2.2.0", + "@smithy/shared-ini-file-loader": "^2.4.0", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/helper-hoist-variables": { - "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, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.535.0", + "license": "Apache-2.0", "dependencies": { - "@babel/types": "^7.22.5" + "@aws-sdk/types": "3.535.0", + "@smithy/property-provider": "^2.2.0", + "@smithy/shared-ini-file-loader": "^2.4.0", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", - "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", - "dev": true, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.554.0", + "license": "Apache-2.0", "dependencies": { - "@babel/types": "^7.23.0" + "@aws-sdk/client-sso": "3.554.0", + "@aws-sdk/token-providers": "3.554.0", + "@aws-sdk/types": "3.535.0", + "@smithy/property-provider": "^2.2.0", + "@smithy/shared-ini-file-loader": "^2.4.0", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/helper-module-imports": { - "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, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.554.0", + "license": "Apache-2.0", "dependencies": { - "@babel/types": "^7.24.0" + "@aws-sdk/client-sts": "3.554.0", + "@aws-sdk/types": "3.535.0", + "@smithy/property-provider": "^2.2.0", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", - "dev": true, + "node_modules/@aws-sdk/lib-storage": { + "version": "3.554.0", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" + "@smithy/abort-controller": "^2.2.0", + "@smithy/middleware-endpoint": "^2.5.1", + "@smithy/smithy-client": "^2.5.1", + "buffer": "5.6.0", + "events": "3.3.0", + "stream-browserify": "3.0.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "@aws-sdk/client-s3": "^3.0.0" } }, - "node_modules/@babel/helper-optimise-call-expression": { - "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, + "node_modules/@aws-sdk/middleware-bucket-endpoint": { + "version": "3.535.0", + "license": "Apache-2.0", "dependencies": { - "@babel/types": "^7.22.5" + "@aws-sdk/types": "3.535.0", + "@aws-sdk/util-arn-parser": "3.535.0", + "@smithy/node-config-provider": "^2.3.0", + "@smithy/protocol-http": "^3.3.0", + "@smithy/types": "^2.12.0", + "@smithy/util-config-provider": "^2.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", - "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", - "dev": true, + "node_modules/@aws-sdk/middleware-expect-continue": { + "version": "3.535.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.535.0", + "@smithy/protocol-http": "^3.3.0", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/helper-remap-async-to-generator": { - "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, + "node_modules/@aws-sdk/middleware-flexible-checksums": { + "version": "3.535.0", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-wrap-function": "^7.22.20" + "@aws-crypto/crc32": "3.0.0", + "@aws-crypto/crc32c": "3.0.0", + "@aws-sdk/types": "3.535.0", + "@smithy/is-array-buffer": "^2.2.0", + "@smithy/protocol-http": "^3.3.0", + "@smithy/types": "^2.12.0", + "@smithy/util-utf8": "^2.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/helper-replace-supers": { - "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, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.535.0", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-member-expression-to-functions": "^7.23.0", - "@babel/helper-optimise-call-expression": "^7.22.5" + "@aws-sdk/types": "3.535.0", + "@smithy/protocol-http": "^3.3.0", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", - "dev": true, + "node_modules/@aws-sdk/middleware-location-constraint": { + "version": "3.535.0", + "license": "Apache-2.0", "dependencies": { - "@babel/types": "^7.22.5" + "@aws-sdk/types": "3.535.0", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "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, + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.535.0", + "license": "Apache-2.0", "dependencies": { - "@babel/types": "^7.22.5" + "@aws-sdk/types": "3.535.0", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dev": true, + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.535.0", + "license": "Apache-2.0", "dependencies": { - "@babel/types": "^7.22.5" + "@aws-sdk/types": "3.535.0", + "@smithy/protocol-http": "^3.3.0", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/helper-string-parser": { - "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, + "node_modules/@aws-sdk/middleware-sdk-s3": { + "version": "3.552.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.535.0", + "@aws-sdk/util-arn-parser": "3.535.0", + "@smithy/node-config-provider": "^2.3.0", + "@smithy/protocol-http": "^3.3.0", + "@smithy/signature-v4": "^2.2.1", + "@smithy/smithy-client": "^2.5.1", + "@smithy/types": "^2.12.0", + "@smithy/util-config-provider": "^2.3.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true, + "node_modules/@aws-sdk/middleware-signing": { + "version": "3.552.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.535.0", + "@smithy/property-provider": "^2.2.0", + "@smithy/protocol-http": "^3.3.0", + "@smithy/signature-v4": "^2.2.1", + "@smithy/types": "^2.12.0", + "@smithy/util-middleware": "^2.2.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/helper-validator-option": { - "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, + "node_modules/@aws-sdk/middleware-ssec": { + "version": "3.537.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.535.0", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", - "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", - "dev": true, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.540.0", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-function-name": "^7.22.5", - "@babel/template": "^7.22.15", - "@babel/types": "^7.22.19" + "@aws-sdk/types": "3.535.0", + "@aws-sdk/util-endpoints": "3.540.0", + "@smithy/protocol-http": "^3.3.0", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/helpers": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz", - "integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==", - "dev": true, + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.535.0", + "license": "Apache-2.0", "dependencies": { - "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.1", - "@babel/types": "^7.24.0" + "@aws-sdk/types": "3.535.0", + "@smithy/node-config-provider": "^2.3.0", + "@smithy/types": "^2.12.0", + "@smithy/util-config-provider": "^2.3.0", + "@smithy/util-middleware": "^2.2.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/highlight": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", - "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", - "dev": true, + "node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.552.0", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "@aws-sdk/middleware-sdk-s3": "3.552.0", + "@aws-sdk/types": "3.535.0", + "@smithy/protocol-http": "^3.3.0", + "@smithy/signature-v4": "^2.2.1", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, + "node_modules/@aws-sdk/token-providers": { + "version": "3.554.0", + "license": "Apache-2.0", "dependencies": { - "color-convert": "^1.9.0" + "@aws-sdk/client-sso-oidc": "3.554.0", + "@aws-sdk/types": "3.535.0", + "@smithy/property-provider": "^2.2.0", + "@smithy/shared-ini-file-loader": "^2.4.0", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=4" + "node": ">=14.0.0" } }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, + "node_modules/@aws-sdk/types": { + "version": "3.535.0", + "license": "Apache-2.0", "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=4" + "node": ">=14.0.0" } }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, + "node_modules/@aws-sdk/util-arn-parser": { + "version": "3.535.0", + "license": "Apache-2.0", "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/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==", - "dev": true, + "tslib": "^2.6.2" + }, "engines": { - "node": ">=4" + "node": ">=14.0.0" } }, - "node_modules/@babel/highlight/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==", - "dev": true, + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.540.0", + "license": "Apache-2.0", "dependencies": { - "has-flag": "^3.0.0" + "@aws-sdk/types": "3.535.0", + "@smithy/types": "^2.12.0", + "@smithy/util-endpoints": "^1.2.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=4" + "node": ">=14.0.0" } }, - "node_modules/@babel/parser": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", - "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.535.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.0.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.4.tgz", - "integrity": "sha512-qpl6vOOEEzTLLcsuqYYo8yDtrTocmu2xkGvgNebvPjT9DTtfFYGmgDqY+rBYXNlqL4s9qLDn6xkrJv4RxAPiTA==", - "dev": true, + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.535.0", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-plugin-utils": "^7.24.0" + "@aws-sdk/types": "3.535.0", + "@smithy/types": "^2.12.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.535.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.535.0", + "@smithy/node-config-provider": "^2.3.0", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } } }, - "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, + "node_modules/@aws-sdk/util-utf8-browser": { + "version": "3.259.0", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "tslib": "^2.3.1" + } + }, + "node_modules/@aws-sdk/xml-builder": { + "version": "3.535.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=14.0.0" } }, - "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==", + "node_modules/@babel/code-frame": { + "version": "7.24.2", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/plugin-transform-optional-chaining": "^7.24.1" + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" } }, - "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==", + "node_modules/@babel/compat-data": { + "version": "7.24.4", "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-plugin-utils": "^7.24.0" - }, + "license": "MIT", "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.24.1.tgz", - "integrity": "sha512-zPEvzFijn+hRvJuX2Vu3KbEBN39LN3f7tW3MQO2LsIs57B26KU+kUc82BdAktS1VCM6libzh45eKGI65lg0cpA==", + "node_modules/@babel/core": { + "version": "7.24.4", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.1", - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/plugin-syntax-decorators": "^7.24.1" + "@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.3", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "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==", + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", "dev": true, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "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==", + "node_modules/@babel/generator": { + "version": "7.24.4", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" + "@babel/types": "^7.22.5" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.15", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-decorators": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.24.1.tgz", - "integrity": "sha512-05RJdO/cCrtVWuAaSn1tS3bH8jbsJa/Y1uD186u6J4C/1mnHFxseeuWpsqr9anvo7TUulev7tm7GDwRV+VuhDw==", + "node_modules/@babel/helper-compilation-targets": { + "version": "7.23.6", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@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" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.24.4", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" + "@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.23.0", + "@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.22.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-syntax-import-assertions": { - "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==", + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "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==", + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.22.15", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@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" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz", - "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==", + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, + "license": "MIT", "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/types": "^7.22.5" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.23.0", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/types": "^7.23.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "node_modules/@babel/helper-module-imports": { + "version": "7.24.3", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/types": "^7.24.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.22.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/types": "^7.22.5" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.0", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, + "license": "MIT", "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.22.20", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@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" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-syntax-typescript": { + "node_modules/@babel/helper-replace-supers": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz", - "integrity": "sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@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" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "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==", + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/types": "^7.22.5" }, "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==", + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "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==", + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", "dev": true, + "license": "MIT", "dependencies": { - "@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" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-async-to-generator": { + "node_modules/@babel/helper-string-parser": { "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.24.1", - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-remap-async-to-generator": "^7.22.20" - }, + "license": "MIT", "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "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==", + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, + "license": "MIT", "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.4.tgz", - "integrity": "sha512-nIFUZIpGKDf9O9ttyRXpHFpKC+X3Y5mtshZONuEUYBomAKoM4y029Jr+uB1bHGPhNmK8YXHevDtKDOLmtRrp6g==", + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, + "license": "MIT", "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-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==", + "node_modules/@babel/helper-wrap-function": { + "version": "7.22.20", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.1", - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-class-static-block": { + "node_modules/@babel/helpers": { "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, + "license": "MIT", "dependencies": { - "@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" + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" } }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.1.tgz", - "integrity": "sha512-ZTIe3W7UejJd3/3R4p7ScyyOoafetUShSf4kCqV0O7F/RiHxVj/wRaRnQlrGwflvcehNA8M42HkAiEDYZu2F1Q==", + "node_modules/@babel/highlight": { + "version": "7.24.2", "dev": true, + "license": "MIT", "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.0", - "@babel/helper-replace-supers": "^7.24.1", - "@babel/helper-split-export-declaration": "^7.22.6", - "globals": "^11.1.0" + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "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==", + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/template": "^7.24.0" + "color-convert": "^1.9.0" }, "engines": { - "node": ">=6.9.0" + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=4" } }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.1.tgz", - "integrity": "sha512-ow8jciWqNxR3RYbSNVuF4U2Jx130nwnBnhRw6N6h1bOejNkABmcI5X5oz29K4alWX7vf1C+o6gtKXikzRKkVdw==", + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" }, "engines": { - "node": ">=6.9.0" + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.4", + "dev": true, + "license": "MIT", + "bin": { + "parser": "bin/babel-parser.js" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6.0.0" } }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "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==", + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.24.4", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@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-transform-duplicate-keys": { + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "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, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -1107,49 +1433,48 @@ "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-dynamic-import": { + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { "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, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" + "@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-transform-exponentiation-operator": { + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { "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, + "license": "MIT", "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@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-transform-export-namespace-from": { + "node_modules/@babel/plugin-proposal-decorators": { "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, + "license": "MIT", "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.1", "@babel/helper-plugin-utils": "^7.24.0", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + "@babel/plugin-syntax-decorators": "^7.24.1" }, "engines": { "node": ">=6.9.0" @@ -1158,15 +1483,10 @@ "@babel/core": "^7.0.0-0" } }, - "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==", + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" - }, + "license": "MIT", "engines": { "node": ">=6.9.0" }, @@ -1174,62 +1494,45 @@ "@babel/core": "^7.0.0-0" } }, - "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==", + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", "dev": true, + "license": "MIT", "dependencies": { - "@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" + "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "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==", + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/plugin-syntax-json-strings": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" + "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "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==", + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" + "@babel/helper-plugin-utils": "^7.12.13" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "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==", + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + "@babel/helper-plugin-utils": "^7.14.5" }, "engines": { "node": ">=6.9.0" @@ -1238,11 +1541,10 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-member-expression-literals": { + "node_modules/@babel/plugin-syntax-decorators": { "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, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -1253,49 +1555,34 @@ "@babel/core": "^7.0.0-0" } }, - "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==", + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" + "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "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==", + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", "dev": true, + "license": "MIT", "dependencies": { - "@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" + "@babel/helper-plugin-utils": "^7.8.3" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-modules-systemjs": { + "node_modules/@babel/plugin-syntax-import-assertions": { "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, + "license": "MIT", "dependencies": { - "@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" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1304,13 +1591,11 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-modules-umd": { + "node_modules/@babel/plugin-syntax-import-attributes": { "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, + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.23.3", "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { @@ -1320,45 +1605,34 @@ "@babel/core": "^7.0.0-0" } }, - "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==", + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" + "@babel/helper-plugin-utils": "^7.10.4" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "@babel/core": "^7.0.0-0" } }, - "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==", + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" + "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "node_modules/@babel/plugin-syntax-jsx": { "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, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1367,32 +1641,78 @@ "@babel/core": "^7.0.0-0" } }, - "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==", + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" + "@babel/helper-plugin-utils": "^7.10.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.1.tgz", - "integrity": "sha512-XjD5f0YqOtebto4HGISLNfiNMTTs6tbkFf2TOqJlYKYmbo+mN9Dnpl4SRoofiziuOWMIyq3sZEUqLo3hLITFEA==", + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.24.1" + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" }, "engines": { "node": ">=6.9.0" @@ -1401,14 +1721,12 @@ "@babel/core": "^7.0.0-0" } }, - "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==", + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-replace-supers": "^7.24.1" + "@babel/helper-plugin-utils": "^7.14.5" }, "engines": { "node": ">=6.9.0" @@ -1417,14 +1735,12 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-optional-catch-binding": { + "node_modules/@babel/plugin-syntax-typescript": { "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, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1433,28 +1749,25 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.1.tgz", - "integrity": "sha512-n03wmDt+987qXwAgcBlnUUivrZBPZ8z1plL0YvgQalLm+ZE5BMhGm94jhxXtA1wzv1Cu2aaOv1BM9vbVttrzSg==", + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" + "@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-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-parameters": { + "node_modules/@babel/plugin-transform-arrow-functions": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.1.tgz", - "integrity": "sha512-8Jl6V24g+Uw5OGPeWNKrKqXPDw2YDjLc53ojwfMcKwlEoETKU9rU0mHUtcg9JntWI/QYzGAXNWEcVHZ+fR+XXg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -1465,14 +1778,15 @@ "@babel/core": "^7.0.0-0" } }, - "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==", + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.24.3", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.1", - "@babel/helper-plugin-utils": "^7.24.0" + "@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" @@ -1481,16 +1795,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-private-property-in-object": { + "node_modules/@babel/plugin-transform-async-to-generator": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.1.tgz", - "integrity": "sha512-pTHxDVa0BpUbvAgX3Gat+7cSciXqUcY9j2VZKTbSB6+VQGpNgNO9ailxTGHSXlqOnX1Hcx1Enme2+yv7VqP9bg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-module-imports": "^7.24.1", "@babel/helper-plugin-utils": "^7.24.0", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + "@babel/helper-remap-async-to-generator": "^7.22.20" }, "engines": { "node": ">=6.9.0" @@ -1499,11 +1811,10 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-property-literals": { + "node_modules/@babel/plugin-transform-block-scoped-functions": { "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, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -1514,14 +1825,12 @@ "@babel/core": "^7.0.0-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==", + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.24.4", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "regenerator-transform": "^0.15.2" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1530,12 +1839,12 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-reserved-words": { + "node_modules/@babel/plugin-transform-class-properties": { "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, + "license": "MIT", "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.1", "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { @@ -1545,18 +1854,35 @@ "@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==", + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.24.4", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.24.3", + "@babel/helper-create-class-features-plugin": "^7.24.4", "@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" + "@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-classes": { + "version": "7.24.1", + "dev": true, + "license": "MIT", + "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.0", + "@babel/helper-replace-supers": "^7.24.1", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" }, "engines": { "node": ">=6.9.0" @@ -1565,20 +1891,25 @@ "@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==", + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.24.1", "dev": true, - "bin": { - "semver": "bin/semver.js" + "license": "MIT", + "dependencies": { + "@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-shorthand-properties": { + "node_modules/@babel/plugin-transform-destructuring": { "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, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -1589,14 +1920,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-spread": { + "node_modules/@babel/plugin-transform-dotall-regex": { "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, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1605,11 +1935,10 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-sticky-regex": { + "node_modules/@babel/plugin-transform-duplicate-keys": { "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, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -1620,13 +1949,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-template-literals": { + "node_modules/@babel/plugin-transform-dynamic-import": { "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, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" }, "engines": { "node": ">=6.9.0" @@ -1635,12 +1964,12 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-typeof-symbol": { + "node_modules/@babel/plugin-transform-exponentiation-operator": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.1.tgz", - "integrity": "sha512-CBfU4l/A+KruSUoW+vTQthwcAdwuqbpRNB8HQKlZABwHRhsdHZ9fezp4Sn18PeAlYxTNiLMlx4xUBV3AWfg1BA==", "dev": true, + "license": "MIT", "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { @@ -1650,16 +1979,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-typescript": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.4.tgz", - "integrity": "sha512-79t3CQ8+oBGk/80SQ8MN3Bs3obf83zJ0YZjDmDaEZN8MqhMI760apl5z6a20kFeMXBwJX99VpKT8CKxEBp5H1g==", + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-create-class-features-plugin": "^7.24.4", "@babel/helper-plugin-utils": "^7.24.0", - "@babel/plugin-syntax-typescript": "^7.24.1" + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" }, "engines": { "node": ">=6.9.0" @@ -1668,13 +1994,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-unicode-escapes": { + "node_modules/@babel/plugin-transform-for-of": { "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, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1683,13 +2009,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-unicode-property-regex": { + "node_modules/@babel/plugin-transform-function-name": { "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, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-function-name": "^7.23.0", "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { @@ -1699,14 +2025,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-unicode-regex": { + "node_modules/@babel/plugin-transform-json-strings": { "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, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-json-strings": "^7.8.3" }, "engines": { "node": ">=6.9.0" @@ -1715,109 +2040,27 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "node_modules/@babel/plugin-transform-literals": { "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, + "license": "MIT", "dependencies": { - "@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" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-env": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.4.tgz", - "integrity": "sha512-7Kl6cSmYkak0FK/FXjSEnLJ1N9T/WA2RkMhu17gZ/dsxKJUuTYNIylahPTzqpLyJN4WhDif8X0XK1R8Wsguo/A==", + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.24.4", - "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-validator-option": "^7.23.5", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.4", - "@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.4", - "@babel/plugin-transform-class-properties": "^7.24.1", - "@babel/plugin-transform-class-static-block": "^7.24.4", - "@babel/plugin-transform-classes": "^7.24.1", - "@babel/plugin-transform-computed-properties": "^7.24.1", - "@babel/plugin-transform-destructuring": "^7.24.1", - "@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.1", - "@babel/plugin-transform-object-super": "^7.24.1", - "@babel/plugin-transform-optional-catch-binding": "^7.24.1", - "@babel/plugin-transform-optional-chaining": "^7.24.1", - "@babel/plugin-transform-parameters": "^7.24.1", - "@babel/plugin-transform-private-methods": "^7.24.1", - "@babel/plugin-transform-private-property-in-object": "^7.24.1", - "@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.1", - "@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" + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" }, "engines": { "node": ">=6.9.0" @@ -1826,40 +2069,43 @@ "@babel/core": "^7.0.0-0" } }, - "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==", + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.24.1", "dev": true, - "bin": { - "semver": "bin/semver.js" + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "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==", + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" + "@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-0 || ^8.0.0-0 <8.0.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-typescript": { + "node_modules/@babel/plugin-transform-modules-commonjs": { "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.24.1.tgz", - "integrity": "sha512-1DBaMmRDpuYQBPWD8Pf/WEwCrtgRHxsZnP4mIy9G/X+hFfbI47Q2G4t1Paakld84+qsk2fSsUPMKg71jkoOOaQ==", "dev": true, + "license": "MIT", "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-validator-option": "^7.23.5", - "@babel/plugin-syntax-jsx": "^7.24.1", - "@babel/plugin-transform-modules-commonjs": "^7.24.1", - "@babel/plugin-transform-typescript": "^7.24.1" + "@babel/helper-simple-access": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1868,845 +2114,9684 @@ "@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.24.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz", - "integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==", + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "regenerator-runtime": "^0.14.0" + "@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" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "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==", + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.23.5", - "@babel/parser": "^7.24.0", - "@babel/types": "^7.24.0" + "@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-0" } }, - "node_modules/@babel/traverse": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", - "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.1", - "@babel/generator": "^7.24.1", - "@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.22.6", - "@babel/parser": "^7.24.1", - "@babel/types": "^7.24.0", - "debug": "^4.3.1", - "globals": "^11.1.0" + "@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" } }, - "node_modules/@babel/types": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", - "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "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/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "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==", + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@sinclair/typebox": "^0.27.8" + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.24.1" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "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-object-super": { + "version": "7.24.1", "dev": true, + "license": "MIT", "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", + "@babel/helper-replace-supers": "^7.24.1" }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-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==", + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.24.1", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-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==", + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.24.1", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "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/@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/@babel/plugin-transform-parameters": { + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { - "node": ">= 8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.24.1", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, "engines": { - "node": ">= 8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { - "node": ">= 8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@nrwl/devkit": { - "version": "18.2.4", - "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-18.2.4.tgz", - "integrity": "sha512-dLK8MMb3eEFWlhtI1kNDNbWIT1Xbrgg3eAQ+Ix/N5JDbxJkJhE28WsIJgQb1NTwe/N87O5JtOpxz4/TsSLJCsQ==", + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@nx/devkit": "18.2.4" + "@babel/helper-plugin-utils": "^7.24.0", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@nrwl/js": { - "version": "18.2.4", - "resolved": "https://registry.npmjs.org/@nrwl/js/-/js-18.2.4.tgz", - "integrity": "sha512-/NZUOoR13BdKsuuuusNXH9wUDpWuPHIvHAQiI0hF16mmQOBJb+xz5M81+AtyTfF4ITKaMn+RV12mLesfo3zwxg==", + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@nx/js": "18.2.4" + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@nrwl/tao": { - "version": "18.2.4", - "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-18.2.4.tgz", - "integrity": "sha512-kgJwZ26F+AzvFXaW5eh1g4HLntPcJ6+EE7JyEvrdRzpw7KxTqWy6Ql7dYys6zGlpP4c3PbsXwdc7tGM3Df2PNg==", + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.24.3", "dev": true, + "license": "MIT", "dependencies": { - "nx": "18.2.4", - "tslib": "^2.3.0" + "@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" }, - "bin": { - "tao": "index.js" + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@nrwl/workspace": { - "version": "18.2.4", - "resolved": "https://registry.npmjs.org/@nrwl/workspace/-/workspace-18.2.4.tgz", - "integrity": "sha512-rlKDKyqwd8IFWwGFhJ0/KW0P+ae6gQEwzpF9P91DLC1BAEJt9gOA0GLKNy7XyhoPX2EvXg/GwDRGMqGxqKnFuQ==", + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", "dev": true, - "dependencies": { - "@nx/workspace": "18.2.4" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@nx/devkit": { - "version": "18.2.4", - "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-18.2.4.tgz", - "integrity": "sha512-Ws3BcA/aeXuwsCQ5e7PYy2H7DswareTOEfgs7izxNyGugpydktVH9DZZTOFNDsc06yzgvyTucDbDQ+JsrJ9PcQ==", + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@nrwl/devkit": "18.2.4", - "ejs": "^3.1.7", - "enquirer": "~2.3.6", - "ignore": "^5.0.4", - "semver": "^7.5.3", - "tmp": "~0.2.1", - "tslib": "^2.3.0", - "yargs-parser": "21.1.1" + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "nx": ">= 16 <= 18" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@nx/js": { - "version": "18.2.4", - "resolved": "https://registry.npmjs.org/@nx/js/-/js-18.2.4.tgz", - "integrity": "sha512-ZZ32tSmd9ZvQ95AeFCCG4mvvbwbqTVB1qHwvpTfkTDPt41Ich+ITf3ugavtIpp/T47yP2KszJWBzTOH3UxlIqQ==", + "node_modules/@babel/plugin-transform-spread": { + "version": "7.24.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/core": "^7.23.2", - "@babel/plugin-proposal-decorators": "^7.22.7", - "@babel/plugin-transform-class-properties": "^7.22.5", - "@babel/plugin-transform-runtime": "^7.23.2", - "@babel/preset-env": "^7.23.2", - "@babel/preset-typescript": "^7.22.5", - "@babel/runtime": "^7.22.6", - "@nrwl/js": "18.2.4", - "@nx/devkit": "18.2.4", - "@nx/workspace": "18.2.4", - "@phenomnomnominal/tsquery": "~5.0.1", - "babel-plugin-const-enum": "^1.0.1", - "babel-plugin-macros": "^2.8.0", - "babel-plugin-transform-typescript-metadata": "^0.3.1", - "chalk": "^4.1.0", - "columnify": "^1.6.0", - "detect-port": "^1.5.1", - "fast-glob": "3.2.7", - "fs-extra": "^11.1.0", - "ignore": "^5.0.4", - "js-tokens": "^4.0.0", - "minimatch": "9.0.3", - "npm-package-arg": "11.0.1", - "npm-run-path": "^4.0.1", - "ora": "5.3.0", - "semver": "^7.5.3", - "source-map-support": "0.5.19", - "ts-node": "10.9.1", - "tsconfig-paths": "^4.1.2", - "tslib": "^2.3.0" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" }, - "peerDependencies": { - "verdaccio": "^5.0.4" + "engines": { + "node": ">=6.9.0" }, - "peerDependenciesMeta": { - "verdaccio": { - "optional": true - } + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@nx/nx-darwin-arm64": { - "version": "18.2.4", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-18.2.4.tgz", - "integrity": "sha512-RYhMImghdyHmwnbNoR2CkLz4Opj9EmuHY3lMfsorg+T4wIOql/iXACrqjnreN7Hy9myJDo1EIbYZ4x8VSxFWtA==", - "cpu": [ - "arm64" - ], + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.24.1", "dev": true, - "optional": true, - "os": [ - "darwin" - ], + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, "engines": { - "node": ">= 10" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@nx/nx-darwin-x64": { - "version": "18.2.4", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-18.2.4.tgz", - "integrity": "sha512-2mXMslSRD/ZoI/oaX+0Mh9J/hucXtNgdwC4YFbp1u8UKquAaQ6hf4uo0s4i+AfLX0F7roMtkFPaG/+MQUJE1Rw==", - "cpu": [ - "x64" - ], + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.24.1", "dev": true, - "optional": true, - "os": [ - "darwin" - ], + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, "engines": { - "node": ">= 10" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@nx/nx-freebsd-x64": { - "version": "18.2.4", - "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-18.2.4.tgz", - "integrity": "sha512-QUiYLvyUT0PS7D8erf49xa1Jyw4Gfev5gtYfME34Twmn/JPx/99ZkBG4wHbzLqRGwlO5K6m6P4qs30Pzfwtw7A==", - "cpu": [ - "x64" - ], + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.24.1", "dev": true, - "optional": true, - "os": [ - "freebsd" - ], + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, "engines": { - "node": ">= 10" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@nx/nx-linux-arm-gnueabihf": { - "version": "18.2.4", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-18.2.4.tgz", - "integrity": "sha512-+fjFciSUhvDV8dPa97Brwb83k3Xa4gHPI2Un8wlpp28Cv4horeGruRZrrifR1VmD2wp2UBIMl5n7YsDP8KvYhQ==", - "cpu": [ - "arm" - ], + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.24.4", "dev": true, - "optional": true, - "os": [ - "linux" - ], + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.24.4", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-typescript": "^7.24.1" + }, "engines": { - "node": ">= 10" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@nx/nx-linux-arm64-gnu": { - "version": "18.2.4", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-18.2.4.tgz", - "integrity": "sha512-lfaTc+AvV56Uv5mXROiRwh2REiI/7IsqeRDfL+prcuuvJ5Oxi2wYVgnmqcHL+ryQnk0Qn7/d+j/BmYHX5Ve5jQ==", - "cpu": [ - "arm64" - ], + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.24.1", "dev": true, - "optional": true, + "license": "MIT", + "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-unicode-property-regex": { + "version": "7.24.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@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/@babel/plugin-transform-unicode-regex": { + "version": "7.24.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@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/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.24.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@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/@babel/preset-env": { + "version": "7.24.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.24.4", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.4", + "@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.4", + "@babel/plugin-transform-class-properties": "^7.24.1", + "@babel/plugin-transform-class-static-block": "^7.24.4", + "@babel/plugin-transform-classes": "^7.24.1", + "@babel/plugin-transform-computed-properties": "^7.24.1", + "@babel/plugin-transform-destructuring": "^7.24.1", + "@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.1", + "@babel/plugin-transform-object-super": "^7.24.1", + "@babel/plugin-transform-optional-catch-binding": "^7.24.1", + "@babel/plugin-transform-optional-chaining": "^7.24.1", + "@babel/plugin-transform-parameters": "^7.24.1", + "@babel/plugin-transform-private-methods": "^7.24.1", + "@babel/plugin-transform-private-property-in-object": "^7.24.1", + "@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.1", + "@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/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.24.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-syntax-jsx": "^7.24.1", + "@babel/plugin-transform-modules-commonjs": "^7.24.1", + "@babel/plugin-transform-typescript": "^7.24.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/runtime": { + "version": "7.24.4", + "devOptional": true, + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", + "@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.22.6", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.24.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@commitlint/cli": { + "version": "17.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/format": "^17.8.1", + "@commitlint/lint": "^17.8.1", + "@commitlint/load": "^17.8.1", + "@commitlint/read": "^17.8.1", + "@commitlint/types": "^17.8.1", + "execa": "^5.0.0", + "lodash.isfunction": "^3.0.9", + "resolve-from": "5.0.0", + "resolve-global": "1.0.0", + "yargs": "^17.0.0" + }, + "bin": { + "commitlint": "cli.js" + }, + "engines": { + "node": ">=v14" + } + }, + "node_modules/@commitlint/config-conventional": { + "version": "17.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "conventional-changelog-conventionalcommits": "^6.1.0" + }, + "engines": { + "node": ">=v14" + } + }, + "node_modules/@commitlint/config-validator": { + "version": "17.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^17.8.1", + "ajv": "^8.11.0" + }, + "engines": { + "node": ">=v14" + } + }, + "node_modules/@commitlint/ensure": { + "version": "17.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^17.8.1", + "lodash.camelcase": "^4.3.0", + "lodash.kebabcase": "^4.1.1", + "lodash.snakecase": "^4.1.1", + "lodash.startcase": "^4.4.0", + "lodash.upperfirst": "^4.3.1" + }, + "engines": { + "node": ">=v14" + } + }, + "node_modules/@commitlint/execute-rule": { + "version": "17.8.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=v14" + } + }, + "node_modules/@commitlint/format": { + "version": "17.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^17.8.1", + "chalk": "^4.1.0" + }, + "engines": { + "node": ">=v14" + } + }, + "node_modules/@commitlint/is-ignored": { + "version": "17.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^17.8.1", + "semver": "7.5.4" + }, + "engines": { + "node": ">=v14" + } + }, + "node_modules/@commitlint/lint": { + "version": "17.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/is-ignored": "^17.8.1", + "@commitlint/parse": "^17.8.1", + "@commitlint/rules": "^17.8.1", + "@commitlint/types": "^17.8.1" + }, + "engines": { + "node": ">=v14" + } + }, + "node_modules/@commitlint/load": { + "version": "17.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/config-validator": "^17.8.1", + "@commitlint/execute-rule": "^17.8.1", + "@commitlint/resolve-extends": "^17.8.1", + "@commitlint/types": "^17.8.1", + "@types/node": "20.5.1", + "chalk": "^4.1.0", + "cosmiconfig": "^8.0.0", + "cosmiconfig-typescript-loader": "^4.0.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "lodash.uniq": "^4.5.0", + "resolve-from": "^5.0.0", + "ts-node": "^10.8.1", + "typescript": "^4.6.4 || ^5.2.2" + }, + "engines": { + "node": ">=v14" + } + }, + "node_modules/@commitlint/load/node_modules/@types/node": { + "version": "20.5.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@commitlint/message": { + "version": "17.8.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=v14" + } + }, + "node_modules/@commitlint/parse": { + "version": "17.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^17.8.1", + "conventional-changelog-angular": "^6.0.0", + "conventional-commits-parser": "^4.0.0" + }, + "engines": { + "node": ">=v14" + } + }, + "node_modules/@commitlint/read": { + "version": "17.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/top-level": "^17.8.1", + "@commitlint/types": "^17.8.1", + "fs-extra": "^11.0.0", + "git-raw-commits": "^2.0.11", + "minimist": "^1.2.6" + }, + "engines": { + "node": ">=v14" + } + }, + "node_modules/@commitlint/resolve-extends": { + "version": "17.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/config-validator": "^17.8.1", + "@commitlint/types": "^17.8.1", + "import-fresh": "^3.0.0", + "lodash.mergewith": "^4.6.2", + "resolve-from": "^5.0.0", + "resolve-global": "^1.0.0" + }, + "engines": { + "node": ">=v14" + } + }, + "node_modules/@commitlint/rules": { + "version": "17.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/ensure": "^17.8.1", + "@commitlint/message": "^17.8.1", + "@commitlint/to-lines": "^17.8.1", + "@commitlint/types": "^17.8.1", + "execa": "^5.0.0" + }, + "engines": { + "node": ">=v14" + } + }, + "node_modules/@commitlint/to-lines": { + "version": "17.8.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=v14" + } + }, + "node_modules/@commitlint/top-level": { + "version": "17.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^5.0.0" + }, + "engines": { + "node": ">=v14" + } + }, + "node_modules/@commitlint/types": { + "version": "17.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0" + }, + "engines": { + "node": ">=v14" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "dev": true, + "license": "MIT", + "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/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@getlarge/nestjs-tools-amqp-transport": { + "resolved": "packages/amqp-transport", + "link": true + }, + "node_modules/@getlarge/nestjs-tools-async-local-storage": { + "resolved": "packages/async-local-storage", + "link": true + }, + "node_modules/@getlarge/nestjs-tools-cluster": { + "resolved": "packages/cluster", + "link": true + }, + "node_modules/@getlarge/nestjs-tools-file-storage": { + "resolved": "packages/file-storage", + "link": true + }, + "node_modules/@getlarge/nestjs-tools-lock": { + "resolved": "packages/lock", + "link": true + }, + "node_modules/@getlarge/typed-event-emitter": { + "resolved": "packages/typed-event-emitter", + "link": true + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@ioredis/as-callback": { + "version": "3.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@ioredis/commands": { + "version": "1.2.0", + "license": "MIT" + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/sprintf-js": { + "version": "1.0.3", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.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": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@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": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.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": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "dev": true, + "license": "MIT", + "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/@jridgewell/resolve-uri": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@lukeed/csprng": { + "version": "1.1.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@nestjs/common": { + "version": "10.3.7", + "license": "MIT", + "dependencies": { + "iterare": "1.2.1", + "tslib": "2.6.2", + "uid": "2.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "class-transformer": "*", + "class-validator": "*", + "reflect-metadata": "^0.1.12 || ^0.2.0", + "rxjs": "^7.1.0" + }, + "peerDependenciesMeta": { + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, + "node_modules/@nestjs/config": { + "version": "3.2.2", + "license": "MIT", + "dependencies": { + "dotenv": "16.4.5", + "dotenv-expand": "10.0.0", + "lodash": "4.17.21", + "uuid": "9.0.1" + }, + "peerDependencies": { + "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", + "rxjs": "^7.1.0" + } + }, + "node_modules/@nestjs/core": { + "version": "10.3.7", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@nuxtjs/opencollective": "0.3.2", + "fast-safe-stringify": "2.1.1", + "iterare": "1.2.1", + "path-to-regexp": "3.2.0", + "tslib": "2.6.2", + "uid": "2.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/microservices": "^10.0.0", + "@nestjs/platform-express": "^10.0.0", + "@nestjs/websockets": "^10.0.0", + "reflect-metadata": "^0.1.12 || ^0.2.0", + "rxjs": "^7.1.0" + }, + "peerDependenciesMeta": { + "@nestjs/microservices": { + "optional": true + }, + "@nestjs/platform-express": { + "optional": true + }, + "@nestjs/websockets": { + "optional": true + } + } + }, + "node_modules/@nestjs/microservices": { + "version": "10.3.7", + "license": "MIT", + "dependencies": { + "iterare": "1.2.1", + "tslib": "2.6.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "@grpc/grpc-js": "*", + "@nestjs/common": "^10.0.0", + "@nestjs/core": "^10.0.0", + "@nestjs/websockets": "^10.0.0", + "amqp-connection-manager": "*", + "amqplib": "*", + "cache-manager": "*", + "ioredis": "*", + "kafkajs": "*", + "mqtt": "*", + "nats": "*", + "reflect-metadata": "^0.1.12 || ^0.2.0", + "rxjs": "^7.1.0" + }, + "peerDependenciesMeta": { + "@grpc/grpc-js": { + "optional": true + }, + "@nestjs/websockets": { + "optional": true + }, + "amqp-connection-manager": { + "optional": true + }, + "amqplib": { + "optional": true + }, + "cache-manager": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "kafkajs": { + "optional": true + }, + "mqtt": { + "optional": true + }, + "nats": { + "optional": true + } + } + }, + "node_modules/@nestjs/platform-express": { + "version": "10.3.7", + "license": "MIT", + "dependencies": { + "body-parser": "1.20.2", + "cors": "2.8.5", + "express": "4.19.2", + "multer": "1.4.4-lts.1", + "tslib": "2.6.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/core": "^10.0.0" + } + }, + "node_modules/@nestjs/schematics": { + "version": "10.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "17.1.2", + "@angular-devkit/schematics": "17.1.2", + "comment-json": "4.2.3", + "jsonc-parser": "3.2.1", + "pluralize": "8.0.0" + }, + "peerDependencies": { + "typescript": ">=4.8.2" + } + }, + "node_modules/@nestjs/testing": { + "version": "10.3.7", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "2.6.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/core": "^10.0.0", + "@nestjs/microservices": "^10.0.0", + "@nestjs/platform-express": "^10.0.0" + }, + "peerDependenciesMeta": { + "@nestjs/microservices": { + "optional": true + }, + "@nestjs/platform-express": { + "optional": true + } + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nrwl/devkit": { + "version": "18.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@nx/devkit": "18.2.4" + } + }, + "node_modules/@nrwl/eslint-plugin-nx": { + "version": "18.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@nx/eslint-plugin": "18.2.4" + } + }, + "node_modules/@nrwl/jest": { + "version": "18.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@nx/jest": "18.2.4" + } + }, + "node_modules/@nrwl/js": { + "version": "18.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@nx/js": "18.2.4" + } + }, + "node_modules/@nrwl/nest": { + "version": "18.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@nx/nest": "18.2.4" + } + }, + "node_modules/@nrwl/node": { + "version": "18.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@nx/node": "18.2.4" + } + }, + "node_modules/@nrwl/tao": { + "version": "18.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "nx": "18.2.4", + "tslib": "^2.3.0" + }, + "bin": { + "tao": "index.js" + } + }, + "node_modules/@nrwl/workspace": { + "version": "18.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@nx/workspace": "18.2.4" + } + }, + "node_modules/@nuxtjs/opencollective": { + "version": "0.3.2", + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "consola": "^2.15.0", + "node-fetch": "^2.6.1" + }, + "bin": { + "opencollective": "bin/opencollective.js" + }, + "engines": { + "node": ">=8.0.0", + "npm": ">=5.0.0" + } + }, + "node_modules/@nx/devkit": { + "version": "18.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@nrwl/devkit": "18.2.4", + "ejs": "^3.1.7", + "enquirer": "~2.3.6", + "ignore": "^5.0.4", + "semver": "^7.5.3", + "tmp": "~0.2.1", + "tslib": "^2.3.0", + "yargs-parser": "21.1.1" + }, + "peerDependencies": { + "nx": ">= 16 <= 18" + } + }, + "node_modules/@nx/eslint": { + "version": "18.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@nx/devkit": "18.2.4", + "@nx/js": "18.2.4", + "@nx/linter": "18.2.4", + "eslint": "^8.0.0", + "tslib": "^2.3.0", + "typescript": "~5.4.2" + }, + "peerDependencies": { + "js-yaml": "4.1.0" + }, + "peerDependenciesMeta": { + "js-yaml": { + "optional": true + } + } + }, + "node_modules/@nx/eslint-plugin": { + "version": "18.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@nrwl/eslint-plugin-nx": "18.2.4", + "@nx/devkit": "18.2.4", + "@nx/js": "18.2.4", + "@typescript-eslint/type-utils": "^7.3.0", + "@typescript-eslint/utils": "^7.3.0", + "chalk": "^4.1.0", + "confusing-browser-globals": "^1.0.9", + "jsonc-eslint-parser": "^2.1.0", + "semver": "^7.5.3", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.13.2 || ^7.0.0", + "eslint-config-prettier": "^9.0.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/@nx/jest": { + "version": "18.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/reporters": "^29.4.1", + "@jest/test-result": "^29.4.1", + "@nrwl/jest": "18.2.4", + "@nx/devkit": "18.2.4", + "@nx/js": "18.2.4", + "@phenomnomnominal/tsquery": "~5.0.1", + "chalk": "^4.1.0", + "identity-obj-proxy": "3.0.0", + "jest-config": "^29.4.1", + "jest-resolve": "^29.4.1", + "jest-util": "^29.4.1", + "minimatch": "9.0.3", + "resolve.exports": "1.1.0", + "tslib": "^2.3.0", + "yargs-parser": "21.1.1" + } + }, + "node_modules/@nx/js": { + "version": "18.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.23.2", + "@babel/plugin-proposal-decorators": "^7.22.7", + "@babel/plugin-transform-class-properties": "^7.22.5", + "@babel/plugin-transform-runtime": "^7.23.2", + "@babel/preset-env": "^7.23.2", + "@babel/preset-typescript": "^7.22.5", + "@babel/runtime": "^7.22.6", + "@nrwl/js": "18.2.4", + "@nx/devkit": "18.2.4", + "@nx/workspace": "18.2.4", + "@phenomnomnominal/tsquery": "~5.0.1", + "babel-plugin-const-enum": "^1.0.1", + "babel-plugin-macros": "^2.8.0", + "babel-plugin-transform-typescript-metadata": "^0.3.1", + "chalk": "^4.1.0", + "columnify": "^1.6.0", + "detect-port": "^1.5.1", + "fast-glob": "3.2.7", + "fs-extra": "^11.1.0", + "ignore": "^5.0.4", + "js-tokens": "^4.0.0", + "minimatch": "9.0.3", + "npm-package-arg": "11.0.1", + "npm-run-path": "^4.0.1", + "ora": "5.3.0", + "semver": "^7.5.3", + "source-map-support": "0.5.19", + "ts-node": "10.9.1", + "tsconfig-paths": "^4.1.2", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "verdaccio": "^5.0.4" + }, + "peerDependenciesMeta": { + "verdaccio": { + "optional": true + } + } + }, + "node_modules/@nx/js/node_modules/bl": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/@nx/js/node_modules/cli-cursor": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@nx/js/node_modules/ora": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "log-symbols": "^4.0.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@nx/js/node_modules/readable-stream": { + "version": "3.6.2", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@nx/js/node_modules/restore-cursor": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@nx/js/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/@nx/js/node_modules/string_decoder": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/@nx/linter": { + "version": "18.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@nx/eslint": "18.2.4" + } + }, + "node_modules/@nx/nest": { + "version": "18.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@nestjs/schematics": "^9.1.0", + "@nrwl/nest": "18.2.4", + "@nx/devkit": "18.2.4", + "@nx/eslint": "18.2.4", + "@nx/js": "18.2.4", + "@nx/node": "18.2.4", + "@phenomnomnominal/tsquery": "~5.0.1", + "tslib": "^2.3.0" + } + }, + "node_modules/@nx/nest/node_modules/@angular-devkit/core": { + "version": "16.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "8.12.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.2.0", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^16.14.0 || >=18.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 + } + } + }, + "node_modules/@nx/nest/node_modules/@angular-devkit/schematics": { + "version": "16.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "16.0.1", + "jsonc-parser": "3.2.0", + "magic-string": "0.30.0", + "ora": "5.4.1", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@nx/nest/node_modules/@nestjs/schematics": { + "version": "9.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "16.0.1", + "@angular-devkit/schematics": "16.0.1", + "jsonc-parser": "3.2.0", + "pluralize": "8.0.0" + }, + "peerDependencies": { + "typescript": ">=4.3.5" + } + }, + "node_modules/@nx/nest/node_modules/jsonc-parser": { + "version": "3.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@nx/nest/node_modules/magic-string": { + "version": "0.30.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.13" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@nx/node": { + "version": "18.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@nrwl/node": "18.2.4", + "@nx/devkit": "18.2.4", + "@nx/eslint": "18.2.4", + "@nx/jest": "18.2.4", + "@nx/js": "18.2.4", + "tslib": "^2.3.0" + } + }, + "node_modules/@nx/nx-darwin-arm64": { + "version": "18.2.4", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nx/workspace": { + "version": "18.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@nrwl/workspace": "18.2.4", + "@nx/devkit": "18.2.4", + "chalk": "^4.1.0", + "enquirer": "~2.3.6", + "nx": "18.2.4", + "tslib": "^2.3.0", + "yargs-parser": "21.1.1" + } + }, + "node_modules/@phenomnomnominal/tsquery": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "esquery": "^1.4.0" + }, + "peerDependencies": { + "typescript": "^3 || ^4 || ^5" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@smithy/abort-controller": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/chunked-blob-reader": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@smithy/chunked-blob-reader-native": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-base64": "^2.3.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@smithy/config-resolver": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^2.3.0", + "@smithy/types": "^2.12.0", + "@smithy/util-config-provider": "^2.3.0", + "@smithy/util-middleware": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/core": { + "version": "1.4.2", + "license": "Apache-2.0", + "dependencies": { + "@smithy/middleware-endpoint": "^2.5.1", + "@smithy/middleware-retry": "^2.3.1", + "@smithy/middleware-serde": "^2.3.0", + "@smithy/protocol-http": "^3.3.0", + "@smithy/smithy-client": "^2.5.1", + "@smithy/types": "^2.12.0", + "@smithy/util-middleware": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "2.3.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^2.3.0", + "@smithy/property-provider": "^2.2.0", + "@smithy/types": "^2.12.0", + "@smithy/url-parser": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-codec": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/crc32": "3.0.0", + "@smithy/types": "^2.12.0", + "@smithy/util-hex-encoding": "^2.2.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@smithy/eventstream-serde-browser": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/eventstream-serde-universal": "^2.2.0", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-config-resolver": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-node": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/eventstream-serde-universal": "^2.2.0", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-universal": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/eventstream-codec": "^2.2.0", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "2.5.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^3.3.0", + "@smithy/querystring-builder": "^2.2.0", + "@smithy/types": "^2.12.0", + "@smithy/util-base64": "^2.3.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@smithy/hash-blob-browser": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/chunked-blob-reader": "^2.2.0", + "@smithy/chunked-blob-reader-native": "^2.2.0", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@smithy/hash-node": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.12.0", + "@smithy/util-buffer-from": "^2.2.0", + "@smithy/util-utf8": "^2.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/hash-stream-node": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.12.0", + "@smithy/util-utf8": "^2.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/invalid-dependency": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/md5-js": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.12.0", + "@smithy/util-utf8": "^2.3.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@smithy/middleware-content-length": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^3.3.0", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-endpoint": { + "version": "2.5.1", + "license": "Apache-2.0", + "dependencies": { + "@smithy/middleware-serde": "^2.3.0", + "@smithy/node-config-provider": "^2.3.0", + "@smithy/shared-ini-file-loader": "^2.4.0", + "@smithy/types": "^2.12.0", + "@smithy/url-parser": "^2.2.0", + "@smithy/util-middleware": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-retry": { + "version": "2.3.1", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^2.3.0", + "@smithy/protocol-http": "^3.3.0", + "@smithy/service-error-classification": "^2.1.5", + "@smithy/smithy-client": "^2.5.1", + "@smithy/types": "^2.12.0", + "@smithy/util-middleware": "^2.2.0", + "@smithy/util-retry": "^2.2.0", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-serde": { + "version": "2.3.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-stack": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-config-provider": { + "version": "2.3.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^2.2.0", + "@smithy/shared-ini-file-loader": "^2.4.0", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "2.5.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^2.2.0", + "@smithy/protocol-http": "^3.3.0", + "@smithy/querystring-builder": "^2.2.0", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/property-provider": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/protocol-http": { + "version": "3.3.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/querystring-builder": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.12.0", + "@smithy/util-uri-escape": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/querystring-parser": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/service-error-classification": { + "version": "2.1.5", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.12.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/shared-ini-file-loader": { + "version": "2.4.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "2.3.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "@smithy/types": "^2.12.0", + "@smithy/util-hex-encoding": "^2.2.0", + "@smithy/util-middleware": "^2.2.0", + "@smithy/util-uri-escape": "^2.2.0", + "@smithy/util-utf8": "^2.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/smithy-client": { + "version": "2.5.1", + "license": "Apache-2.0", + "dependencies": { + "@smithy/middleware-endpoint": "^2.5.1", + "@smithy/middleware-stack": "^2.2.0", + "@smithy/protocol-http": "^3.3.0", + "@smithy/types": "^2.12.0", + "@smithy/util-stream": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "2.12.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/url-parser": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/querystring-parser": "^2.2.0", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@smithy/util-base64": { + "version": "2.3.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "@smithy/util-utf8": "^2.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-body-length-browser": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@smithy/util-body-length-node": { + "version": "2.3.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-config-provider": { + "version": "2.3.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "2.2.1", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^2.2.0", + "@smithy/smithy-client": "^2.5.1", + "@smithy/types": "^2.12.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node": { + "version": "2.3.1", + "license": "Apache-2.0", + "dependencies": { + "@smithy/config-resolver": "^2.2.0", + "@smithy/credential-provider-imds": "^2.3.0", + "@smithy/node-config-provider": "^2.3.0", + "@smithy/property-provider": "^2.2.0", + "@smithy/smithy-client": "^2.5.1", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-endpoints": { + "version": "1.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^2.3.0", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@smithy/util-hex-encoding": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-middleware": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-retry": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/service-error-classification": "^2.1.5", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@smithy/util-stream": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/fetch-http-handler": "^2.5.0", + "@smithy/node-http-handler": "^2.5.0", + "@smithy/types": "^2.12.0", + "@smithy/util-base64": "^2.3.0", + "@smithy/util-buffer-from": "^2.2.0", + "@smithy/util-hex-encoding": "^2.2.0", + "@smithy/util-utf8": "^2.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-uri-escape": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-waiter": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^2.2.0", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@swc-node/core": { + "version": "1.13.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@swc/core": ">= 1.3", + "@swc/types": ">= 0.1" + } + }, + "node_modules/@swc-node/register": { + "version": "1.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@swc-node/core": "^1.12.0", + "@swc-node/sourcemap-support": "^0.4.0", + "colorette": "^2.0.20", + "debug": "^4.3.4", + "pirates": "^4.0.6", + "tslib": "^2.6.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@swc/core": ">= 1.3", + "typescript": ">= 4.3" + } + }, + "node_modules/@swc-node/sourcemap-support": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "source-map-support": "^0.5.21", + "tslib": "^2.6.2" + } + }, + "node_modules/@swc-node/sourcemap-support/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@swc-node/sourcemap-support/node_modules/source-map-support": { + "version": "0.5.21", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/@swc/core": { + "version": "1.3.107", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.1", + "@swc/types": "^0.1.5" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.3.107", + "@swc/core-darwin-x64": "1.3.107", + "@swc/core-linux-arm-gnueabihf": "1.3.107", + "@swc/core-linux-arm64-gnu": "1.3.107", + "@swc/core-linux-arm64-musl": "1.3.107", + "@swc/core-linux-x64-gnu": "1.3.107", + "@swc/core-linux-x64-musl": "1.3.107", + "@swc/core-win32-arm64-msvc": "1.3.107", + "@swc/core-win32-ia32-msvc": "1.3.107", + "@swc/core-win32-x64-msvc": "1.3.107" + }, + "peerDependencies": { + "@swc/helpers": "^0.5.0" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.3.107", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@swc/helpers": { + "version": "0.5.10", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@swc/types": { + "version": "0.1.6", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/amqplib": { + "version": "0.10.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cookiejar": { + "version": "2.1.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/express": { + "version": "4.17.21", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ioredis-mock": { + "version": "8.2.5", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*", + "ioredis": ">=5" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.12", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/methods": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/minimist": { + "version": "1.2.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "18.19.31", + "devOptional": true, + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/qs": { + "version": "6.9.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/readable-stream": { + "version": "4.0.11", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "safe-buffer": "~5.1.1" + } + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/superagent": { + "version": "8.1.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/cookiejar": "^2.1.5", + "@types/methods": "^1.1.4", + "@types/node": "*" + } + }, + "node_modules/@types/supertest": { + "version": "6.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/methods": "^1.1.4", + "@types/superagent": "^8.1.0" + } + }, + "node_modules/@types/uuid": { + "version": "9.0.8", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.32", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.7.0", + "@typescript-eslint/type-utils": "7.7.0", + "@typescript-eslint/utils": "7.7.0", + "@typescript-eslint/visitor-keys": "7.7.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.6.0", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.7.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "7.7.0", + "@typescript-eslint/types": "7.7.0", + "@typescript-eslint/typescript-estree": "7.7.0", + "@typescript-eslint/visitor-keys": "7.7.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.7.0", + "@typescript-eslint/visitor-keys": "7.7.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "7.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "7.7.0", + "@typescript-eslint/utils": "7.7.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "7.7.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.7.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "7.7.0", + "@typescript-eslint/visitor-keys": "7.7.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": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.4", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.6.0", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/@typescript-eslint/utils": { + "version": "7.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.15", + "@types/semver": "^7.5.8", + "@typescript-eslint/scope-manager": "7.7.0", + "@typescript-eslint/types": "7.7.0", + "@typescript-eslint/typescript-estree": "7.7.0", + "semver": "^7.6.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.6.0", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.7.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "dev": true, + "license": "ISC" + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/@yarnpkg/parsers": { + "version": "3.0.0-rc.46", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "js-yaml": "^3.10.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=14.15.0" + } + }, + "node_modules/@yarnpkg/parsers/node_modules/argparse": { + "version": "1.0.10", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@yarnpkg/parsers/node_modules/js-yaml": { + "version": "3.14.1", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@yarnpkg/parsers/node_modules/sprintf-js": { + "version": "1.0.3", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@zkochan/js-yaml": { + "version": "0.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "devOptional": true, + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.11.3", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/address": { + "version": "1.2.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/amqp-connection-manager": { + "version": "4.1.14", + "license": "MIT", + "dependencies": { + "promise-breaker": "^6.0.0" + }, + "engines": { + "node": ">=10.0.0", + "npm": ">5.0.0" + }, + "peerDependencies": { + "amqplib": "*" + } + }, + "node_modules/amqplib": { + "version": "0.10.4", + "license": "MIT", + "dependencies": { + "@acuminous/bitsyntax": "^0.1.2", + "buffer-more-ints": "~1.0.0", + "readable-stream": "1.x >=1.1.9", + "url-parse": "~1.5.10" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/arg": { + "version": "4.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/array-ify": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/array-includes": { + "version": "3.1.8", + "dev": true, + "license": "MIT", + "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-timsort": { + "version": "1.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/array-union": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.5", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/async": { + "version": "3.2.5", + "dev": true, + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/audit-ci": { + "version": "6.6.1", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "cross-spawn": "^7.0.3", + "escape-string-regexp": "^4.0.0", + "event-stream": "4.0.1", + "jju": "^1.4.0", + "JSONStream": "^1.3.5", + "readline-transform": "1.0.0", + "semver": "^7.0.0", + "yargs": "^17.0.0" + }, + "bin": { + "audit-ci": "dist/bin.js" + }, + "engines": { + "node": ">=12.9.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axios": { + "version": "1.6.8", + "dev": true, + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-const-enum": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-typescript": "^7.3.3", + "@babel/traverse": "^7.16.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "dev": true, + "license": "BSD-3-Clause", + "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-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "dev": true, + "license": "BSD-3-Clause", + "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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "dev": true, + "license": "MIT", + "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": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-plugin-macros": { + "version": "2.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "cosmiconfig": "^6.0.0", + "resolve": "^1.12.0" + } + }, + "node_modules/babel-plugin-macros/node_modules/cosmiconfig": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-macros/node_modules/yaml": { + "version": "1.10.2", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.10", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.1", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.1", + "core-js-compat": "^3.36.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-transform-typescript-metadata": { + "version": "0.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "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": "29.6.3", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bl": { + "version": "6.0.12", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/readable-stream": "^4.0.0", + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^4.2.0" + } + }, + "node_modules/bl/node_modules/buffer": { + "version": "6.0.3", + "devOptional": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "4.5.2", + "devOptional": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/bl/node_modules/safe-buffer": { + "version": "5.2.1", + "devOptional": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bl/node_modules/string_decoder": { + "version": "1.3.0", + "devOptional": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/body-parser": { + "version": "1.20.2", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/bowser": { + "version": "2.11.0", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.0", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "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" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "5.6.0", + "license": "MIT", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "license": "MIT" + }, + "node_modules/buffer-more-ints": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/builtins": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-keys": { + "version": "6.2.2", + "dev": true, + "license": "MIT", + "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_modules/caniuse-lite": { + "version": "1.0.30001610", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.3", + "dev": true, + "license": "MIT" + }, + "node_modules/cli-cursor": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "2.6.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/cluster-key-slot": { + "version": "1.1.2", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/co": { + "version": "4.6.0", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "dev": true, + "license": "MIT" + }, + "node_modules/columnify": { + "version": "1.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "strip-ansi": "^6.0.1", + "wcwidth": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "11.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/comment-json": { + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "array-timsort": "^1.0.3", + "core-util-is": "^1.0.3", + "esprima": "^4.0.1", + "has-own-prop": "^2.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/commist": { + "version": "3.2.0", + "devOptional": true, + "license": "MIT" + }, + "node_modules/compare-func": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "node_modules/component-emitter": { + "version": "1.3.1", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "2.0.0", + "devOptional": true, + "engines": [ + "node >= 6.0" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "3.6.2", + "devOptional": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/concat-stream/node_modules/safe-buffer": { + "version": "5.2.1", + "devOptional": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/concat-stream/node_modules/string_decoder": { + "version": "1.3.0", + "devOptional": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/confusing-browser-globals": { + "version": "1.0.11", + "dev": true, + "license": "MIT" + }, + "node_modules/consola": { + "version": "2.15.3", + "license": "MIT" + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-disposition/node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/content-type": { + "version": "1.0.5", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/conventional-changelog-angular": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/conventional-changelog-conventionalcommits": { + "version": "6.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/conventional-commits-parser": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-text-path": "^1.0.1", + "JSONStream": "^1.3.5", + "meow": "^8.1.2", + "split2": "^3.2.2" + }, + "bin": { + "conventional-commits-parser": "cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.6.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "license": "MIT" + }, + "node_modules/cookiejar": { + "version": "2.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/core-js-compat": { + "version": "3.36.1", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.5", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "dev": true, + "license": "MIT", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cosmiconfig-typescript-loader": { + "version": "4.4.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=v14.21.3" + }, + "peerDependencies": { + "@types/node": "*", + "cosmiconfig": ">=7", + "ts-node": ">=10", + "typescript": ">=4" + } + }, + "node_modules/create-jest": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/dargs": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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/debug": { + "version": "4.3.4", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "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/map-obj": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "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/delayed-stream": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/denque": { + "version": "2.1.0", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-port": { + "version": "1.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "address": "^1.0.1", + "debug": "4" + }, + "bin": { + "detect": "bin/detect-port.js", + "detect-port": "bin/detect-port.js" + } + }, + "node_modules/dezalgo": { + "version": "1.0.4", + "dev": true, + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "16.4.5", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dotenv-expand": { + "version": "10.0.0", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/ejs": { + "version": "3.1.10", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.737", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "10.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enquirer": { + "version": "2.3.6", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.23.3", + "dev": true, + "license": "MIT", + "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", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "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/escalade": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "dev": true, + "license": "MIT", + "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-config-prettier": { + "version": "9.1.0", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.29.1", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/json5": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-import/node_modules/strip-bom": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/tsconfig-paths": { + "version": "3.15.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/eslint-plugin-max-params-no-constructor": { + "version": "0.0.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-simple-import-sort": { + "version": "12.1.0", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=5.0.0" + } + }, + "node_modules/eslint-plugin-unused-imports": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-rule-composer": "^0.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "6 - 7", + "eslint": "8" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + } + } + }, + "node_modules/eslint-rule-composer": { + "version": "0.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "dev": true, + "license": "BSD-2-Clause", + "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-visitor-keys": { + "version": "3.4.3", + "dev": true, + "license": "Apache-2.0", + "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", + "dev": true, + "license": "MIT", + "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/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "dev": true, + "license": "BSD-2-Clause", + "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", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-stream": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "duplexer": "^0.1.1", + "from": "^0.1.7", + "map-stream": "0.0.7", + "pause-stream": "^0.0.11", + "split": "^1.0.1", + "stream-combiner": "^0.2.2", + "through": "^2.3.8" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/events": { + "version": "3.3.0", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "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/exit": { + "version": "0.1.2", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/express": { + "version": "4.19.2", + "license": "MIT", + "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", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/express/node_modules/path-to-regexp": { + "version": "0.1.7", + "license": "MIT" + }, + "node_modules/express/node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.2.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "license": "MIT" + }, + "node_modules/fast-unique-numbers": { + "version": "8.0.13", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.8", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.1.0" + } + }, + "node_modules/fast-xml-parser": { + "version": "4.2.5", + "funding": [ + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + }, + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "strnum": "^1.0.5" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fengari": { + "version": "0.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "readline-sync": "^1.4.9", + "sprintf-js": "^1.1.1", + "tmp": "^0.0.33" + } + }, + "node_modules/fengari-interop": { + "version": "0.1.3", + "dev": true, + "license": "MIT", + "peerDependencies": { + "fengari": "^0.1.0" + } + }, + "node_modules/fengari/node_modules/tmp": { + "version": "0.0.33", + "dev": true, + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/filelist": { + "version": "1.0.4", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "license": "MIT", + "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", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/find-up": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/formidable": { + "version": "2.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "dezalgo": "^1.0.4", + "hexoid": "^1.0.0", + "once": "^1.4.0", + "qs": "^6.11.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/from": { + "version": "0.1.7", + "dev": true, + "license": "MIT" + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/fs-extra": { + "version": "11.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "dev": true, + "license": "MIT", + "optional": true, "os": [ - "linux" + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "dev": true, + "license": "MIT", + "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/functions-have-names": { + "version": "1.2.3", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "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/git-raw-commits": { + "version": "2.0.11", + "dev": true, + "license": "MIT", + "dependencies": { + "dargs": "^7.0.0", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "split2": "^3.0.0", + "through2": "^4.0.0" + }, + "bin": { + "git-raw-commits": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "dev": true, + "license": "ISC", + "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/glob-parent": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/global-dirs": { + "version": "0.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "^1.3.4" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "dev": true, + "license": "MIT", + "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/globby/node_modules/fast-glob": { + "version": "3.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/globby/node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "dev": true, + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/hard-rejection": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/harmony-reflect": { + "version": "1.6.2", + "dev": true, + "license": "(Apache-2.0 OR MPL-1.1)" + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-own-prop": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/help-me": { + "version": "5.0.0", + "devOptional": true, + "license": "MIT" + }, + "node_modules/hexoid": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "license": "MIT", + "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/human-signals": { + "version": "2.1.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/husky": { + "version": "9.0.11", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.mjs" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/identity-obj-proxy": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "harmony-reflect": "^1.4.6" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "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_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "dev": true, + "license": "ISC" + }, + "node_modules/internal-slot": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ioredis": { + "version": "5.3.2", + "license": "MIT", + "dependencies": { + "@ioredis/commands": "^1.1.1", + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.4", + "denque": "^2.1.0", + "lodash.defaults": "^4.2.0", + "lodash.isarguments": "^3.1.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" + }, + "engines": { + "node": ">=12.22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ioredis" + } + }, + "node_modules/ioredis-mock": { + "version": "8.9.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@ioredis/as-callback": "^3.0.0", + "@ioredis/commands": "^1.2.0", + "fengari": "^0.1.4", + "fengari-interop": "^0.1.3", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12.22" + }, + "peerDependencies": { + "@types/ioredis-mock": "^8", + "ioredis": "^5" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-text-path": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "text-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "0.0.1", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.2", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/iterare": { + "version": "1.2.1", + "license": "ISC", + "engines": { + "node": ">=6" + } + }, + "node_modules/jake": { + "version": "10.8.7", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jake/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/jake/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/babel-plugin-macros": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/jest-circus/node_modules/cosmiconfig": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "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" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-circus/node_modules/dedent": { + "version": "1.5.3", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/jest-circus/node_modules/yaml": { + "version": "1.10.2", + "dev": true, + "license": "ISC", + "optional": true, + "peer": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.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": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve/node_modules/resolve.exports": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-runner/node_modules/source-map-support": { + "version": "0.5.13", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util/node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jju": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/js-sdsl": { + "version": "4.3.0", + "devOptional": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-eslint-parser": { + "version": "2.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.5.0", + "eslint-visitor-keys": "^3.0.0", + "espree": "^9.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + } + }, + "node_modules/jsonc-parser": { + "version": "3.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "license": "MIT" + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "dev": true, + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/lines-and-columns": { + "version": "2.0.4", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/lint-staged": { + "version": "15.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "5.3.0", + "commander": "11.1.0", + "debug": "4.3.4", + "execa": "8.0.1", + "lilconfig": "3.0.0", + "listr2": "8.0.1", + "micromatch": "4.0.5", + "pidtree": "0.6.0", + "string-argv": "0.3.2", + "yaml": "2.3.4" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/lint-staged/node_modules/chalk": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/execa": { + "version": "8.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/get-stream": { + "version": "8.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/human-signals": { + "version": "5.0.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/lint-staged/node_modules/is-stream": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/mimic-fn": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/npm-run-path": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/onetime": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/path-key": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/signal-exit": { + "version": "4.1.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/lint-staged/node_modules/strip-final-newline": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2": { + "version": "8.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.0.0", + "rfdc": "^1.3.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "license": "MIT" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "license": "MIT" + }, + "node_modules/lodash.isarguments": { + "version": "3.1.0", + "license": "MIT" + }, + "node_modules/lodash.isfunction": { + "version": "3.0.9", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.kebabcase": { + "version": "4.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.mergewith": { + "version": "4.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.startcase": { + "version": "4.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.upperfirst": { + "version": "4.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^6.2.0", + "cli-cursor": "^4.0.0", + "slice-ansi": "^7.0.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-escapes": { + "version": "6.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "dev": true, + "license": "ISC" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/map-obj": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/map-stream": { + "version": "0.0.7", + "dev": true, + "license": "MIT" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/meow": { + "version": "8.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "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" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/type-fest": { + "version": "0.18.1", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/yargs-parser": { + "version": "20.2.9", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "license": "MIT" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "9.0.3", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minimist-options": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mqtt": { + "version": "5.5.2", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/readable-stream": "^4.0.5", + "@types/ws": "^8.5.9", + "commist": "^3.2.0", + "concat-stream": "^2.0.0", + "debug": "^4.3.4", + "help-me": "^5.0.0", + "lru-cache": "^10.0.1", + "minimist": "^1.2.8", + "mqtt": "^5.2.0", + "mqtt-packet": "^9.0.0", + "number-allocator": "^1.0.14", + "readable-stream": "^4.4.2", + "reinterval": "^1.1.0", + "rfdc": "^1.3.0", + "split2": "^4.2.0", + "worker-timers": "^7.1.4", + "ws": "^8.14.2" + }, + "bin": { + "mqtt": "build/bin/mqtt.js", + "mqtt_pub": "build/bin/pub.js", + "mqtt_sub": "build/bin/sub.js" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/mqtt-packet": { + "version": "9.0.0", + "devOptional": true, + "license": "MIT", + "dependencies": { + "bl": "^6.0.8", + "debug": "^4.3.4", + "process-nextick-args": "^2.0.1" + } + }, + "node_modules/mqtt/node_modules/buffer": { + "version": "6.0.3", + "devOptional": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/mqtt/node_modules/lru-cache": { + "version": "10.2.0", + "devOptional": true, + "license": "ISC", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/mqtt/node_modules/readable-stream": { + "version": "4.5.2", + "devOptional": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/mqtt/node_modules/safe-buffer": { + "version": "5.2.1", + "devOptional": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/mqtt/node_modules/split2": { + "version": "4.2.0", + "devOptional": true, + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/mqtt/node_modules/string_decoder": { + "version": "1.3.0", + "devOptional": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "license": "MIT" + }, + "node_modules/multer": { + "version": "1.4.4-lts.1", + "license": "MIT", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.0.0", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/multer/node_modules/concat-stream": { + "version": "1.6.2", + "engines": [ + "node >= 0.8" ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/multer/node_modules/isarray": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/multer/node_modules/readable-stream": { + "version": "2.3.8", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/multer/node_modules/string_decoder": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "license": "MIT", "engines": { - "node": ">= 10" + "node": ">= 0.6" } }, - "node_modules/@nx/nx-linux-arm64-musl": { - "version": "18.2.4", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-18.2.4.tgz", - "integrity": "sha512-U6eoLTQmbxUWU9kZxx6hsYN4zmmOrsDDeW+i3aj5aeahfYlmyz6TsT0V3FSB70WGJC5aMVgEi4RkntQMKkm5vQ==", - "cpu": [ - "arm64" - ], + "node_modules/node-abort-controller": { + "version": "3.1.1", + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-int64": { + "version": "0.4.0", "dev": true, - "optional": true, - "os": [ - "linux" - ], + "license": "MIT" + }, + "node_modules/node-machine-id": { + "version": "1.1.12", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.14", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-package-data": { + "version": "3.0.3", + "dev": true, + "license": "BSD-2-Clause", + "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": ">=10" } }, - "node_modules/@nx/nx-linux-x64-gnu": { - "version": "18.2.4", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-18.2.4.tgz", - "integrity": "sha512-q8WcJhmcRNORkKjax6WcUwMJe/1mQs+RYlUkGqmi7tD7lfcLSqdLPJVjqVmQAwmy1Wh/MHPsbqRwSerUnCxB1A==", - "cpu": [ - "x64" - ], + "node_modules/normalize-path": { + "version": "3.0.0", "dev": true, - "optional": true, - "os": [ - "linux" - ], + "license": "MIT", "engines": { - "node": ">= 10" + "node": ">=0.10.0" } }, - "node_modules/@nx/nx-linux-x64-musl": { - "version": "18.2.4", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-18.2.4.tgz", - "integrity": "sha512-0MDuoPgHa6kkBrjg7hwZ2qQivhJbh3lk7r3q4osDrqZcGxq5XVJqeAmYFyChQy4dbQfUm4hhYkEfzpU8M2lnvQ==", - "cpu": [ - "x64" - ], + "node_modules/npm-package-arg": { + "version": "11.0.1", "dev": true, - "optional": true, - "os": [ - "linux" - ], + "license": "ISC", + "dependencies": { + "hosted-git-info": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, "engines": { - "node": ">= 10" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@nx/nx-win32-arm64-msvc": { - "version": "18.2.4", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-18.2.4.tgz", - "integrity": "sha512-uLhSRtfnXzN000Qf27GOjEPXzd4/jBWqv2x419IMh+AEtKHuCEpQNBUAyLvBbQ79SMr+FmCXHB8AeeJ7bEUiRw==", - "cpu": [ - "arm64" - ], + "node_modules/npm-package-arg/node_modules/hosted-git-info": { + "version": "7.0.1", "dev": true, - "optional": true, - "os": [ - "win32" - ], + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, "engines": { - "node": ">= 10" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@nx/nx-win32-x64-msvc": { - "version": "18.2.4", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-18.2.4.tgz", - "integrity": "sha512-Y52Afz02Ub1kRZXd6NUTwPMjKQqBKZ35e5dUEpl14na2fWvdgdMz4bYOBPUcmQrovlxBGhmFXtFzxkdW3zyRbQ==", - "cpu": [ - "x64" - ], + "node_modules/npm-package-arg/node_modules/lru-cache": { + "version": "10.2.0", "dev": true, - "optional": true, - "os": [ - "win32" - ], + "license": "ISC", "engines": { - "node": ">= 10" + "node": "14 || >=16.14" } }, - "node_modules/@nx/workspace": { + "node_modules/npm-run-path": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/number-allocator": { + "version": "1.0.14", + "devOptional": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.1", + "js-sdsl": "4.3.0" + } + }, + "node_modules/nx": { "version": "18.2.4", - "resolved": "https://registry.npmjs.org/@nx/workspace/-/workspace-18.2.4.tgz", - "integrity": "sha512-c3Bca6aBwhpMegvAXAyKO8+dBBZOej8EIVo7m22IXL7APbq+hRetoc0LBCa/wTRcEZpYYPGrN1PzfFZqME21+g==", "dev": true, + "hasInstallScript": true, + "license": "MIT", "dependencies": { - "@nrwl/workspace": "18.2.4", - "@nx/devkit": "18.2.4", + "@nrwl/tao": "18.2.4", + "@yarnpkg/lockfile": "^1.1.0", + "@yarnpkg/parsers": "3.0.0-rc.46", + "@zkochan/js-yaml": "0.0.6", + "axios": "^1.6.0", "chalk": "^4.1.0", + "cli-cursor": "3.1.0", + "cli-spinners": "2.6.1", + "cliui": "^8.0.1", + "dotenv": "~16.3.1", + "dotenv-expand": "~10.0.0", "enquirer": "~2.3.6", - "nx": "18.2.4", + "figures": "3.2.0", + "flat": "^5.0.2", + "fs-extra": "^11.1.0", + "ignore": "^5.0.4", + "jest-diff": "^29.4.1", + "js-yaml": "4.1.0", + "jsonc-parser": "3.2.0", + "lines-and-columns": "~2.0.3", + "minimatch": "9.0.3", + "node-machine-id": "1.1.12", + "npm-run-path": "^4.0.1", + "open": "^8.4.0", + "ora": "5.3.0", + "semver": "^7.5.3", + "string-width": "^4.2.3", + "strong-log-transformer": "^2.1.0", + "tar-stream": "~2.2.0", + "tmp": "~0.2.1", + "tsconfig-paths": "^4.1.2", "tslib": "^2.3.0", + "yargs": "^17.6.2", "yargs-parser": "21.1.1" + }, + "bin": { + "nx": "bin/nx.js", + "nx-cloud": "bin/nx-cloud.js" + }, + "optionalDependencies": { + "@nx/nx-darwin-arm64": "18.2.4", + "@nx/nx-darwin-x64": "18.2.4", + "@nx/nx-freebsd-x64": "18.2.4", + "@nx/nx-linux-arm-gnueabihf": "18.2.4", + "@nx/nx-linux-arm64-gnu": "18.2.4", + "@nx/nx-linux-arm64-musl": "18.2.4", + "@nx/nx-linux-x64-gnu": "18.2.4", + "@nx/nx-linux-x64-musl": "18.2.4", + "@nx/nx-win32-arm64-msvc": "18.2.4", + "@nx/nx-win32-x64-msvc": "18.2.4" + }, + "peerDependencies": { + "@swc-node/register": "^1.8.0", + "@swc/core": "^1.3.85" + }, + "peerDependenciesMeta": { + "@swc-node/register": { + "optional": true + }, + "@swc/core": { + "optional": true + } } }, - "node_modules/@phenomnomnominal/tsquery": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@phenomnomnominal/tsquery/-/tsquery-5.0.1.tgz", - "integrity": "sha512-3nVv+e2FQwsW8Aw6qTU6f+1rfcJ3hrcnvH/mu9i8YhxO+9sqbOfpL8m6PbET5+xKOlz/VSbp0RoYWYCtIsnmuA==", + "node_modules/nx/node_modules/bl": { + "version": "4.1.0", "dev": true, + "license": "MIT", "dependencies": { - "esquery": "^1.4.0" - }, - "peerDependencies": { - "typescript": "^3 || ^4 || ^5" + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" } }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true - }, - "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/nx/node_modules/cli-cursor": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } }, - "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/nx/node_modules/dotenv": { + "version": "16.3.2", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } }, - "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/nx/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" }, - "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/nx/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "node_modules/@yarnpkg/lockfile": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", - "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", - "dev": true + "node_modules/nx/node_modules/jsonc-parser": { + "version": "3.2.0", + "dev": true, + "license": "MIT" }, - "node_modules/@yarnpkg/parsers": { - "version": "3.0.0-rc.46", - "resolved": "https://registry.npmjs.org/@yarnpkg/parsers/-/parsers-3.0.0-rc.46.tgz", - "integrity": "sha512-aiATs7pSutzda/rq8fnuPwTglyVwjM22bNnK2ZgjrpAjQHSSl3lztd2f9evst1W/qnC58DRz7T7QndUDumAR4Q==", + "node_modules/nx/node_modules/ora": { + "version": "5.3.0", "dev": true, + "license": "MIT", "dependencies": { - "js-yaml": "^3.10.0", - "tslib": "^2.4.0" + "bl": "^4.0.3", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "log-symbols": "^4.0.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" }, "engines": { - "node": ">=14.15.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@yarnpkg/parsers/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/nx/node_modules/readable-stream": { + "version": "3.6.2", "dev": true, + "license": "MIT", "dependencies": { - "sprintf-js": "~1.0.2" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } - }, - "node_modules/@yarnpkg/parsers/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==", + }, + "node_modules/nx/node_modules/restore-cursor": { + "version": "3.1.0", "dev": true, + "license": "MIT", "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">=8" } }, - "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/nx/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/nx/node_modules/string_decoder": { + "version": "1.3.0", "dev": true, + "license": "MIT", "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "safe-buffer": "~5.2.0" } }, - "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "node_modules/nx/node_modules/string-width": { + "version": "4.2.3", "dev": true, - "bin": { - "acorn": "bin/acorn" + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=0.4.0" + "node": ">=8" } }, - "node_modules/acorn-walk": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", - "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", - "dev": true, + "node_modules/object-assign": { + "version": "4.1.1", + "license": "MIT", "engines": { - "node": ">=0.4.0" + "node": ">=0.10.0" } }, - "node_modules/address": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", - "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", - "dev": true, - "engines": { - "node": ">= 10.0.0" + "node_modules/object-inspect": { + "version": "1.13.1", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "node_modules/object-keys": { + "version": "1.1.1", "dev": true, + "license": "MIT", "engines": { - "node": ">=6" + "node": ">= 0.4" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/object.assign": { + "version": "4.1.5", "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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/object.fromentries": { + "version": "2.0.8", "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "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/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/axios": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", - "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "node_modules/object.groupby": { + "version": "1.0.3", "dev": true, + "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/babel-plugin-const-enum": { + "node_modules/object.values": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-const-enum/-/babel-plugin-const-enum-1.2.0.tgz", - "integrity": "sha512-o1m/6iyyFnp9MRsK1dHF3bneqyf3AlM2q3A/YbgQr2pCat6B6XJVDv2TXqzfY2RYUi4mak6WAksSBPlyYGx9dg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-typescript": "^7.3.3", - "@babel/traverse": "^7.16.0" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/babel-plugin-macros": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz", - "integrity": "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==", - "dev": true, + "node_modules/on-finished": { + "version": "2.4.1", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.7.2", - "cosmiconfig": "^6.0.0", - "resolve": "^1.12.0" + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" } }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.10", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.10.tgz", - "integrity": "sha512-rpIuu//y5OX6jVU+a5BCn1R5RSZYWAl2Nar76iwaOdycqb6JPxediskWFMMl7stfwNJR4b7eiQvh5fB5TEQJTQ==", + "node_modules/once": { + "version": "1.4.0", "dev": true, + "license": "ISC", "dependencies": { - "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.6.1", - "semver": "^6.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "wrappy": "1" } }, - "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==", + "node_modules/onetime": { + "version": "5.1.2", "dev": true, - "bin": { - "semver": "bin/semver.js" + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "node_modules/open": { + "version": "8.4.2", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.1", - "core-js-compat": "^3.36.1" + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.1.tgz", - "integrity": "sha512-JfTApdE++cgcTWjsiCQlLyFBMbTUft9ja17saCc93lgV33h4tuCVj7tlvu//qpLwaG+3yEz7/KhahGrUMkVq9g==", + "node_modules/optionator": { + "version": "0.9.3", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.1" + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/babel-plugin-transform-typescript-metadata": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-typescript-metadata/-/babel-plugin-transform-typescript-metadata-0.3.2.tgz", - "integrity": "sha512-mWEvCQTgXQf48yDqgN7CH50waTyYBeP2Lpqx4nNWab9sxEpdXVeKgfj1qYI2/TgUPQtNFZ85i3PemRtnXVYYJg==", + "node_modules/ora": { + "version": "5.4.1", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0" + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/base64-js": { - "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", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/bl": { + "node_modules/ora/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, + "license": "MIT", "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, - "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==", + "node_modules/ora/node_modules/cli-cursor": { + "version": "3.1.0", "dev": true, + "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "node_modules/ora/node_modules/readable-stream": { + "version": "3.6.2", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, "engines": { - "node": ">=8" + "node": ">= 6" } }, - "node_modules/browserslist": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", - "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "node_modules/ora/node_modules/restore-cursor": { + "version": "3.1.0", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "license": "MIT", "dependencies": { - "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" + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" }, "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + "node": ">=8" } }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "node_modules/ora/node_modules/safe-buffer": { + "version": "5.2.1", "dev": true, "funding": [ { @@ -2722,1375 +11807,1285 @@ "url": "https://feross.org/support" } ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "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 + "license": "MIT" }, - "node_modules/builtins": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.1.0.tgz", - "integrity": "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==", + "node_modules/ora/node_modules/string_decoder": { + "version": "1.3.0", "dev": true, + "license": "MIT", "dependencies": { - "semver": "^7.0.0" + "safe-buffer": "~5.2.0" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "node_modules/os-tmpdir": { + "version": "1.0.2", "dev": true, + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001610", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001610.tgz", - "integrity": "sha512-QFutAY4NgaelojVMjY63o6XlZyORPaLfyMnsl3HgnWdJUcX6K0oaJymHjH8PT5Gk7sTm8rvC/c5COUQKXqmOMA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "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/p-limit": { + "version": "3.1.0", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "yocto-queue": "^0.1.0" }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "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==", + "node_modules/p-locate": { + "version": "5.0.0", "dev": true, + "license": "MIT", "dependencies": { - "restore-cursor": "^3.1.0" + "p-limit": "^3.0.2" }, "engines": { - "node": ">=8" - } - }, - "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, - "engines": { - "node": ">=6" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "node_modules/p-try": { + "version": "2.2.0", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.8" + "node": ">=6" } }, - "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/parent-module": { + "version": "1.0.1", "dev": true, + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "callsites": "^3.0.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=6" } }, - "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/columnify": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.6.0.tgz", - "integrity": "sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==", + "node_modules/parse-json": { + "version": "5.2.0", "dev": true, + "license": "MIT", "dependencies": { - "strip-ansi": "^6.0.1", - "wcwidth": "^1.0.0" + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" }, "engines": { - "node": ">=8.0.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "node_modules/parse-json/node_modules/lines-and-columns": { + "version": "1.2.4", "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, + "license": "MIT" + }, + "node_modules/parseurl": { + "version": "1.3.3", + "license": "MIT", "engines": { "node": ">= 0.8" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "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/core-js-compat": { - "version": "3.36.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.1.tgz", - "integrity": "sha512-Dk997v9ZCt3X/npqzyGdTlq6t7lDBhZwGvV94PKzDArjp7BTRm7WlDAXYd/OWdeFHO8OChQYRJNJvUCqCbrtKA==", - "dev": true, - "dependencies": { - "browserslist": "^4.23.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "node_modules/path-exists": { + "version": "4.0.0", "dev": true, - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" - }, + "license": "MIT", "engines": { "node": ">=8" } }, - "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/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/path-is-absolute": { + "version": "1.0.1", "dev": true, - "dependencies": { - "ms": "2.1.2" - }, + "license": "MIT", "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "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": ">=0.10.0" } }, - "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==", + "node_modules/path-key": { + "version": "3.1.1", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "node_modules/path-parse": { + "version": "1.0.7", "dev": true, - "engines": { - "node": ">=0.4.0" - } + "license": "MIT" }, - "node_modules/detect-port": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.5.1.tgz", - "integrity": "sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==", - "dev": true, - "dependencies": { - "address": "^1.0.1", - "debug": "4" - }, - "bin": { - "detect": "bin/detect-port.js", - "detect-port": "bin/detect-port.js" - } + "node_modules/path-to-regexp": { + "version": "3.2.0", + "license": "MIT" }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "node_modules/path-type": { + "version": "4.0.0", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.3.1" + "node": ">=8" } }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "node_modules/pause-stream": { + "version": "0.0.11", "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "license": [ + "MIT", + "Apache2" + ], + "dependencies": { + "through": "~2.3" } }, - "node_modules/dotenv": { - "version": "16.3.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.2.tgz", - "integrity": "sha512-HTlk5nmhkm8F6JcdXvHIzaorzCoziNQT9mGxLPVXW8wJF1TiGSL60ZGB4gHWabHOaMmWmhvk2/lPHfnBiT78AQ==", + "node_modules/picocolors": { + "version": "1.0.0", "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/motdotla/dotenv?sponsor=1" - } + "license": "ISC" }, - "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==", + "node_modules/picomatch": { + "version": "3.0.1", "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "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/ejs": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", - "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "node_modules/pidtree": { + "version": "0.6.0", "dev": true, - "dependencies": { - "jake": "^10.8.5" - }, + "license": "MIT", "bin": { - "ejs": "bin/cli.js" + "pidtree": "bin/pidtree.js" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.736", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.736.tgz", - "integrity": "sha512-Rer6wc3ynLelKNM4lOCg7/zPQj8tPOCB2hzD32PX9wd3hgRRi9MxEbmkFCokzcEhRVMiOVLjnL9ig9cefJ+6+Q==", - "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==", - "dev": true + "node": ">=0.10" + } }, - "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==", + "node_modules/pirates": { + "version": "4.0.6", "dev": true, - "dependencies": { - "once": "^1.4.0" + "license": "MIT", + "engines": { + "node": ">= 6" } }, - "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/pkg-dir": { + "version": "4.2.0", "dev": true, + "license": "MIT", "dependencies": { - "ansi-colors": "^4.1.1" + "find-up": "^4.0.0" }, "engines": { - "node": ">=8.6" + "node": ">=8" } }, - "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==", + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", "dev": true, + "license": "MIT", "dependencies": { - "is-arrayish": "^0.2.1" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, "engines": { - "node": ">=6" + "node": ">=8" } }, - "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==", + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, "engines": { - "node": ">=0.8.0" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "node_modules/pluralize": { + "version": "8.0.0", "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, + "license": "MIT", "engines": { - "node": ">=0.10" + "node": ">=4" } }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/possible-typed-array-names": { + "version": "1.0.0", "dev": true, + "license": "MIT", "engines": { - "node": ">=4.0" + "node": ">= 0.4" } }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "node_modules/prelude-ls": { + "version": "1.2.1", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.8.0" } }, - "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/prettier": { + "version": "2.8.8", "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" + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" }, "engines": { - "node": ">=8" + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "node_modules/pretty-format": { + "version": "29.7.0", "dev": true, + "license": "MIT", "dependencies": { - "reusify": "^1.0.4" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "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==", + "node_modules/proc-log": { + "version": "3.0.0", "dev": true, - "dependencies": { - "minimatch": "^5.0.1" + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "node_modules/process": { + "version": "0.11.10", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "license": "MIT" + }, + "node_modules/promise-breaker": { + "version": "6.0.0", + "license": "MIT" + }, + "node_modules/prompts": { + "version": "2.4.2", "dev": true, + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.1" + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" }, "engines": { - "node": ">=10" + "node": ">= 6" } }, - "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, + "node_modules/proxy-addr": { + "version": "2.0.7", + "license": "MIT", "dependencies": { - "to-regex-range": "^5.0.1" + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" }, "engines": { - "node": ">=8" + "node": ">= 0.10" } }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "node_modules/proxy-from-env": { + "version": "1.1.0", "dev": true, - "bin": { - "flat": "cli.js" + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" } }, - "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==", + "node_modules/pure-rand": { + "version": "6.1.0", "dev": true, "funding": [ { "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" } ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } + "license": "MIT" }, - "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==", - "dev": true, + "node_modules/qs": { + "version": "6.11.0", + "license": "BSD-3-Clause", "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "side-channel": "^1.0.4" }, "engines": { - "node": ">= 6" + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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/querystringify": { + "version": "2.2.0", + "license": "MIT" }, - "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==", + "node_modules/queue-microtask": { + "version": "1.2.3", "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/quick-lru": { + "version": "4.0.1", + "dev": true, + "license": "MIT", "engines": { - "node": ">=14.14" + "node": ">=8" } }, - "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/range-parser": { + "version": "1.2.1", + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "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, + "node_modules/raw-body": { + "version": "2.5.2", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, "engines": { - "node": ">=6.9.0" + "node": ">= 0.8" } }, - "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==", + "node_modules/react-is": { + "version": "18.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/read-pkg": { + "version": "5.2.0", "dev": true, + "license": "MIT", + "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": "6.* || 8.* || >= 10.*" + "node": ">=8" } }, - "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==", + "node_modules/read-pkg-up": { + "version": "7.0.1", "dev": true, + "license": "MIT", "dependencies": { - "is-glob": "^4.0.1" + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" }, "engines": { - "node": ">= 6" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "4.1.0", "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "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/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/read-pkg-up/node_modules/locate-path": { + "version": "5.0.0", "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, "engines": { "node": ">=8" } }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "node_modules/read-pkg-up/node_modules/p-limit": { + "version": "2.3.0", "dev": true, + "license": "MIT", "dependencies": { - "function-bind": "^1.1.2" + "p-try": "^2.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/hosted-git-info": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", - "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", + "node_modules/read-pkg-up/node_modules/p-locate": { + "version": "4.1.0", "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^10.0.1" + "p-limit": "^2.2.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": ">=8" } }, - "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", - "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { - "node": "14 || >=16.14" + "node": ">=8" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] + "license": "ISC" }, - "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/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", "dev": true, - "engines": { - "node": ">= 4" + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, - "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/read-pkg/node_modules/semver": { + "version": "5.7.2", "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "node_modules/readable-stream": { + "version": "1.1.14", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } }, - "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/readline-sync": { + "version": "1.4.10", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } }, - "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==", + "node_modules/readline-transform": { + "version": "1.0.0", "dev": true, - "dependencies": { - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "license": "MIT", + "engines": { + "node": ">=6" } }, - "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/redent": { + "version": "3.0.0", "dev": true, - "bin": { - "is-docker": "cli.js" + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" }, "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, + "node_modules/redis-errors": { + "version": "1.2.0", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/is-fullwidth-code-point": { + "node_modules/redis-parser": { "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==", - "dev": true, + "license": "MIT", + "dependencies": { + "redis-errors": "^1.0.0" + }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "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, + "node_modules/redlock": { + "version": "v5.0.0-beta.2", + "license": "MIT", "dependencies": { - "is-extglob": "^2.1.1" + "node-abort-controller": "^3.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=12" } }, - "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==", + "node_modules/reflect-metadata": { + "version": "0.1.14", + "license": "Apache-2.0" + }, + "node_modules/regenerate": { + "version": "1.4.2", + "dev": true, + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "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==", + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "devOptional": true, + "license": "MIT" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", "dev": true, - "engines": { - "node": ">=0.12.0" + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.4" } }, - "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/regexp.prototype.flags": { + "version": "1.5.2", "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "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/regexpu-core": { + "version": "5.3.2", "dev": true, + "license": "MIT", "dependencies": { - "is-docker": "^2.0.0" + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/jake": { - "version": "10.8.7", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz", - "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==", + "node_modules/regjsparser": { + "version": "0.9.1", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.4", - "minimatch": "^3.1.2" + "jsesc": "~0.5.0" }, "bin": { - "jake": "bin/cli.js" - }, - "engines": { - "node": ">=10" + "regjsparser": "bin/parser" } }, - "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==", + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "bin": { + "jsesc": "bin/jsesc" } }, - "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/reinterval": { + "version": "1.1.0", + "devOptional": true, + "license": "MIT" + }, + "node_modules/repeat-string": { + "version": "1.6.1", "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "license": "MIT", "engines": { - "node": "*" + "node": ">=0.10" } }, - "node_modules/jest-diff": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "node_modules/require-directory": { + "version": "2.1.1", "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, + "license": "MIT", "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=0.10.0" } }, - "node_modules/jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "node_modules/require-from-string": { + "version": "2.0.2", "dev": true, + "license": "MIT", "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=0.10.0" } }, - "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==", - "dev": true + "node_modules/requires-port": { + "version": "1.0.0", + "license": "MIT" }, - "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/resolve": { + "version": "1.22.8", "dev": true, + "license": "MIT", "dependencies": { - "argparse": "^2.0.1" + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { - "js-yaml": "bin/js-yaml.js" + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "node_modules/resolve-global": { + "version": "1.0.0", "dev": true, - "bin": { - "jsesc": "bin/jsesc" + "license": "MIT", + "dependencies": { + "global-dirs": "^0.1.1" }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "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/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "node_modules/resolve.exports": { + "version": "1.1.0", "dev": true, - "bin": { - "json5": "lib/cli.js" - }, + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=10" } }, - "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/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "node_modules/restore-cursor": { + "version": "4.0.0", "dev": true, + "license": "MIT", "dependencies": { - "universalify": "^2.0.0" + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lines-and-columns": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.4.tgz", - "integrity": "sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==", + "node_modules/reusify": { + "version": "1.0.4", "dev": true, + "license": "MIT", "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "iojs": ">=1.0.0", + "node": ">=0.10.0" } }, - "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/rfdc": { + "version": "1.3.1", + "devOptional": true, + "license": "MIT" }, - "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==", + "node_modules/rimraf": { + "version": "3.0.2", "dev": true, + "license": "ISC", "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" + "glob": "^7.1.3" }, - "engines": { - "node": ">=10" + "bin": { + "rimraf": "bin.js" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "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==", + "node_modules/run-parallel": { + "version": "1.2.0", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", "dependencies": { - "yallist": "^3.0.2" + "queue-microtask": "^1.2.2" } }, - "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/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" + "node_modules/rxjs": { + "version": "7.8.1", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" } }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "node_modules/safe-array-concat": { + "version": "1.1.2", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" }, "engines": { - "node": ">=8.6" + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", "dev": true, - "engines": { - "node": ">= 0.6" - } + "license": "MIT" }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "node_modules/safe-buffer": { + "version": "5.1.2", + "license": "MIT" + }, + "node_modules/safe-regex-test": { + "version": "1.0.3", "dev": true, + "license": "MIT", "dependencies": { - "mime-db": "1.52.0" + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "node_modules/safer-buffer": { + "version": "2.1.2", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.5.4", "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, "engines": { - "node": ">=6" + "node": ">=10" } }, - "node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", "dev": true, + "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "yallist": "^4.0.0" }, "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=10" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "node_modules/semver/node_modules/yallist": { + "version": "4.0.0", "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "license": "ISC" + }, + "node_modules/send": { + "version": "0.18.0", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" } }, - "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==", - "dev": true + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } }, - "node_modules/node-machine-id": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/node-machine-id/-/node-machine-id-1.1.12.tgz", - "integrity": "sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==", - "dev": true + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" }, - "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/send/node_modules/ms": { + "version": "2.1.3", + "license": "MIT" }, - "node_modules/npm-package-arg": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.1.tgz", - "integrity": "sha512-M7s1BD4NxdAvBKUPqqRW957Xwcl/4Zvo8Aj+ANrzvIPzGJZElrH7Z//rSaec2ORcND6FHHLnZeY8qgTpXDMFQQ==", - "dev": true, + "node_modules/serve-static": { + "version": "1.15.0", + "license": "MIT", "dependencies": { - "hosted-git-info": "^7.0.0", - "proc-log": "^3.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^5.0.0" + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": ">= 0.8.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/set-function-length": { + "version": "1.2.2", + "license": "MIT", "dependencies": { - "path-key": "^3.0.0" + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" }, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/nx": { - "version": "18.2.4", - "resolved": "https://registry.npmjs.org/nx/-/nx-18.2.4.tgz", - "integrity": "sha512-GxqJcDOhfLa9jsPmip0jG73CZKA96wCryss2DhixCiCU66I3GLYF4+585ObO8Tx7Z1GqhT92RaNGjCxjMIwaPg==", + "node_modules/set-function-name": { + "version": "2.0.2", "dev": true, - "hasInstallScript": true, + "license": "MIT", "dependencies": { - "@nrwl/tao": "18.2.4", - "@yarnpkg/lockfile": "^1.1.0", - "@yarnpkg/parsers": "3.0.0-rc.46", - "@zkochan/js-yaml": "0.0.6", - "axios": "^1.6.0", - "chalk": "^4.1.0", - "cli-cursor": "3.1.0", - "cli-spinners": "2.6.1", - "cliui": "^8.0.1", - "dotenv": "~16.3.1", - "dotenv-expand": "~10.0.0", - "enquirer": "~2.3.6", - "figures": "3.2.0", - "flat": "^5.0.2", - "fs-extra": "^11.1.0", - "ignore": "^5.0.4", - "jest-diff": "^29.4.1", - "js-yaml": "4.1.0", - "jsonc-parser": "3.2.0", - "lines-and-columns": "~2.0.3", - "minimatch": "9.0.3", - "node-machine-id": "1.1.12", - "npm-run-path": "^4.0.1", - "open": "^8.4.0", - "ora": "5.3.0", - "semver": "^7.5.3", - "string-width": "^4.2.3", - "strong-log-transformer": "^2.1.0", - "tar-stream": "~2.2.0", - "tmp": "~0.2.1", - "tsconfig-paths": "^4.1.2", - "tslib": "^2.3.0", - "yargs": "^17.6.2", - "yargs-parser": "21.1.1" - }, - "bin": { - "nx": "bin/nx.js", - "nx-cloud": "bin/nx-cloud.js" - }, - "optionalDependencies": { - "@nx/nx-darwin-arm64": "18.2.4", - "@nx/nx-darwin-x64": "18.2.4", - "@nx/nx-freebsd-x64": "18.2.4", - "@nx/nx-linux-arm-gnueabihf": "18.2.4", - "@nx/nx-linux-arm64-gnu": "18.2.4", - "@nx/nx-linux-arm64-musl": "18.2.4", - "@nx/nx-linux-x64-gnu": "18.2.4", - "@nx/nx-linux-x64-musl": "18.2.4", - "@nx/nx-win32-arm64-msvc": "18.2.4", - "@nx/nx-win32-x64-msvc": "18.2.4" - }, - "peerDependencies": { - "@swc-node/register": "^1.8.0", - "@swc/core": "^1.3.85" + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" }, - "peerDependenciesMeta": { - "@swc-node/register": { - "optional": true - }, - "@swc/core": { - "optional": true - } + "engines": { + "node": ">= 0.4" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "node_modules/setprototypeof": { + "version": "1.2.0", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", "dev": true, + "license": "MIT", "dependencies": { - "wrappy": "1" + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "node_modules/shebang-regex": { + "version": "3.0.0", "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "license": "MIT", "dependencies": { - "mimic-fn": "^2.1.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" }, "engines": { - "node": ">=6" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "node_modules/signal-exit": { + "version": "3.0.7", + "dev": true, + "license": "ISC" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "5.0.0", "dev": true, + "license": "MIT", "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" }, "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "node_modules/ora": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", - "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==", + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.1", "dev": true, - "dependencies": { - "bl": "^4.0.3", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "log-symbols": "^4.0.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "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==", + "node_modules/source-map": { + "version": "0.7.4", "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, + "license": "BSD-3-Clause", "engines": { - "node": ">=6" + "node": ">= 8" } }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "node_modules/source-map-support": { + "version": "0.5.19", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" } }, - "node_modules/parse-json/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 - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", "dev": true, + "license": "BSD-3-Clause", "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "node_modules/spdx-correct": { + "version": "3.2.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "node_modules/spdx-exceptions": { + "version": "2.5.0", "dev": true, - "engines": { - "node": ">=8" + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "node_modules/spdx-license-ids": { + "version": "3.0.17", + "dev": true, + "license": "CC0-1.0" }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "node_modules/split": { + "version": "1.0.1", "dev": true, - "engines": { - "node": ">=8.6" + "license": "MIT", + "dependencies": { + "through": "2" }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "engines": { + "node": "*" } }, - "node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "node_modules/split2": { + "version": "3.2.2", "dev": true, + "license": "ISC", "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "readable-stream": "^3.0.0" + } + }, + "node_modules/split2/node_modules/readable-stream": { + "version": "3.6.2", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 6" } }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/split2/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/split2/node_modules/string_decoder": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "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==", + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", "dev": true, + "license": "MIT", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=8" } }, - "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/standard-as-callback": { + "version": "2.1.0", + "license": "MIT" }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, + "node_modules/statuses": { + "version": "2.0.1", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "license": "MIT", + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "node_modules/stream-browserify/node_modules/readable-stream": { + "version": "3.6.2", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/stream-browserify/node_modules/safe-buffer": { + "version": "5.2.1", "funding": [ { "type": "github", @@ -4104,394 +13099,464 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, - "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true + "node_modules/stream-browserify/node_modules/string_decoder": { + "version": "1.3.0", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/stream-combiner": { + "version": "0.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "duplexer": "~0.1.1", + "through": "~2.3.4" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "0.10.31", + "license": "MIT" + }, + "node_modules/string-argv": { + "version": "0.3.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } }, - "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==", + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", "dev": true, + "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">= 6" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", - "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "node_modules/string.prototype.trim": { + "version": "1.2.9", "dev": true, + "license": "MIT", "dependencies": { - "regenerate": "^1.4.2" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">=4" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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==", - "dev": true - }, - "node_modules/regenerator-transform": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", - "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "node_modules/string.prototype.trimend": { + "version": "1.0.8", "dev": true, + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.8.4" + "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/regexpu-core": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", - "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", "dev": true, + "license": "MIT", "dependencies": { - "@babel/regjsgen": "^0.8.0", - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.1.0" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">=4" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "node_modules/strip-ansi": { + "version": "6.0.1", "dev": true, + "license": "MIT", "dependencies": { - "jsesc": "~0.5.0" + "ansi-regex": "^5.0.1" }, - "bin": { - "regjsparser": "bin/parser" + "engines": { + "node": ">=8" } }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "node_modules/strip-bom": { + "version": "4.0.0", "dev": true, - "bin": { - "jsesc": "bin/jsesc" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "node_modules/strip-final-newline": { + "version": "2.0.0", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "node_modules/strip-indent": { + "version": "3.0.0", "dev": true, + "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" + "min-indent": "^1.0.0" }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=8" } }, - "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/strip-json-comments": { + "version": "3.1.1", "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "node_modules/strnum": { + "version": "1.0.5", + "license": "MIT" + }, + "node_modules/strong-log-transformer": { + "version": "2.1.0", "dev": true, + "license": "Apache-2.0", "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "duplexer": "^0.1.1", + "minimist": "^1.2.0", + "through": "^2.3.4" + }, + "bin": { + "sl-log-transformer": "bin/sl-log-transformer.js" }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "node_modules/superagent": { + "version": "8.1.2", "dev": true, + "license": "MIT", + "dependencies": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.4", + "debug": "^4.3.4", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.0", + "formidable": "^2.1.2", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.0", + "semver": "^7.3.8" + }, "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" + "node": ">=6.4.0 <13 || >=14" } }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "node_modules/superagent/node_modules/mime": { + "version": "2.6.0", "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" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "node_modules/supertest": { + "version": "6.3.4", "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "methods": "^1.1.2", + "superagent": "^8.1.2" }, "engines": { - "node": ">=10" + "node": ">=6.4.0" } }, - "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==", - "dev": true, + "node_modules/supports-color": { + "version": "7.2.0", + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=8" } }, - "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==", - "dev": true - }, - "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/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "node_modules/tar-stream": { + "version": "2.2.0", "dev": true, + "license": "MIT", "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" } }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "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==", + "node_modules/tar-stream/node_modules/bl": { + "version": "4.1.0", "dev": true, + "license": "MIT", "dependencies": { - "safe-buffer": "~5.2.0" + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" } }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/tar-stream/node_modules/readable-stream": { + "version": "3.6.2", "dev": true, + "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, "engines": { - "node": ">=8" + "node": ">= 6" + } + }, + "node_modules/tar-stream/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/tar-stream/node_modules/string_decoder": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" } }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/test-exclude": { + "version": "6.0.0", "dev": true, + "license": "ISC", "dependencies": { - "ansi-regex": "^5.0.1" + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" }, "engines": { "node": ">=8" } }, - "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==", + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.11", "dev": true, - "engines": { - "node": ">=4" + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "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==", + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", "dev": true, + "license": "ISC", "dependencies": { - "duplexer": "^0.1.1", - "minimist": "^1.2.0", - "through": "^2.3.4" - }, - "bin": { - "sl-log-transformer": "bin/sl-log-transformer.js" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=4" + "node": "*" } }, - "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/text-extensions": { + "version": "1.9.0", "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=0.10" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "node_modules/text-table": { + "version": "0.2.0", "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "license": "MIT" + }, + "node_modules/through": { + "version": "2.3.8", + "dev": true, + "license": "MIT" + }, + "node_modules/through2": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "3" } }, - "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/through2/node_modules/readable-stream": { + "version": "3.6.2", "dev": true, + "license": "MIT", "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" + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, "engines": { - "node": ">=6" + "node": ">= 6" } }, - "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/through2/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/through2/node_modules/string_decoder": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } }, "node_modules/tmp": { "version": "0.2.3", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", - "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=14.14" } }, + "node_modules/tmpl": { + "version": "1.0.5", + "dev": true, + "license": "BSD-3-Clause" + }, "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, + "license": "MIT", "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==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -4499,11 +13564,82 @@ "node": ">=8.0" } }, + "node_modules/toidentifier": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "license": "MIT" + }, + "node_modules/trim-newlines": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-jest": { + "version": "29.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.3", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "^7.5.3", + "yargs-parser": "^21.0.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, "node_modules/ts-node": { "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", "dev": true, + "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -4533,49 +13669,207 @@ "@types/node": "*", "typescript": ">=2.7" }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tsconfig-paths": { + "version": "4.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "dev": true, + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "license": "MIT" + }, + "node_modules/typescript": { + "version": "5.4.5", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uid": { + "version": "2.0.2", + "license": "MIT", + "dependencies": { + "@lukeed/csprng": "^1.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/tsconfig-paths": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "node_modules/unbox-primitive": { + "version": "1.0.2", "dev": true, + "license": "MIT", "dependencies": { - "json5": "^2.2.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" }, - "engines": { - "node": ">=6" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true + "node_modules/undici-types": { + "version": "5.26.5", + "devOptional": true, + "license": "MIT" }, "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", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/unicode-match-property-ecmascript": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, + "license": "MIT", "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", "unicode-property-aliases-ecmascript": "^2.0.0" @@ -4586,35 +13880,37 @@ }, "node_modules/unicode-match-property-value-ecmascript": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/unicode-property-aliases-ecmascript": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "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, + "license": "MIT", "engines": { "node": ">= 10.0.0" } }, + "node_modules/unpipe": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/update-browserslist-db": { "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": [ { @@ -4630,6 +13926,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "escalade": "^3.1.1", "picocolors": "^1.0.0" @@ -4641,23 +13938,75 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "9.0.1", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } }, "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 + "dev": true, + "license": "MIT" + }, + "node_modules/v8-to-istanbul": { + "version": "9.2.0", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } }, "node_modules/validate-npm-package-name": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", - "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", "dev": true, + "license": "ISC", "dependencies": { "builtins": "^5.0.0" }, @@ -4665,67 +14014,240 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/vary": { + "version": "1.1.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, "node_modules/wcwidth": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "dev": true, + "license": "MIT", "dependencies": { "defaults": "^1.0.3" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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/worker-timers": { + "version": "7.1.7", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.24.4", + "tslib": "^2.6.2", + "worker-timers-broker": "^6.1.7", + "worker-timers-worker": "^7.0.70" + } + }, + "node_modules/worker-timers-broker": { + "version": "6.1.7", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.24.4", + "fast-unique-numbers": "^8.0.13", + "tslib": "^2.6.2", + "worker-timers-worker": "^7.0.70" + } + }, + "node_modules/worker-timers-worker": { + "version": "7.0.70", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.24.4", + "tslib": "^2.6.2" + } + }, "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": "9.0.0", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "dev": true, + "license": "ISC", + "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.16.0", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "license": "MIT", + "engines": { + "node": ">=0.4" + } }, "node_modules/y18n": { "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/yallist": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "dev": true, + "license": "ISC" }, "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.3.4", "dev": true, + "license": "ISC", "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/yargs": { "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, + "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -4741,21 +14263,130 @@ }, "node_modules/yargs-parser": { "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, + "license": "ISC", "engines": { "node": ">=12" } }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/yn": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/amqp-transport": { + "name": "@getlarge/nestjs-tools-amqp-transport", + "version": "0.5.1", + "license": "Apache-2.0", + "dependencies": { + "@getlarge/typed-event-emitter": "0.1.1", + "tslib": "^2.3.0", + "uuid": "^9.0.1" + }, + "peerDependencies": { + "@nestjs/common": "10", + "@nestjs/microservices": "10", + "amqp-connection-manager": "4", + "amqplib": "0.10", + "promise-breaker": "6.0.0", + "rxjs": "7" + } + }, + "packages/async-local-storage": { + "name": "@getlarge/nestjs-tools-async-local-storage", + "version": "0.2.2", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@nestjs/common": "10", + "@nestjs/core": "10", + "rxjs": "^7.8.0" + } + }, + "packages/cluster": { + "name": "@getlarge/nestjs-tools-cluster", + "version": "0.15.5", + "license": "Apache-2.0", + "dependencies": { + "@getlarge/typed-event-emitter": "0.1.1", + "tslib": "^2.3.0" + } + }, + "packages/file-storage": { + "name": "@getlarge/nestjs-tools-file-storage", + "version": "0.8.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@aws-sdk/client-s3": "3", + "@aws-sdk/lib-storage": "3", + "@nestjs/common": "10" + } + }, + "packages/lock": { + "name": "@getlarge/nestjs-tools-lock", + "version": "0.7.0", + "license": "Apache-2.0", + "dependencies": { + "redlock": "^5.0.0-beta.2", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@nestjs/common": "10", + "ioredis": "^5.3.2" + } + }, + "packages/typed-event-emitter": { + "name": "@getlarge/typed-event-emitter", + "version": "0.1.1", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.3.0" + } } } } diff --git a/package.json b/package.json index 7b0b720..9a6ce38 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,109 @@ { "name": "nestjs-tools", - "version": "0.0.0", - "license": "MIT", - "scripts": {}, + "description": "Tools for NestJS applications", + "version": "0.1.0", + "license": "Apache-2.0", + "homepage": "https://github.com/getlarge/nestjs-tools#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/getlarge/nestjs-tools.git" + }, + "bugs": { + "url": "https://github.com/getlarge/nestjs-tools/issues" + }, + "engines": { + "node": ">=14", + "npm": ">=7" + }, + "scripts": { + "format": "nx format", + "format:all": "prettier --write \"packages/**/*.{ts,json}\"", + "cleanup": "nx run-many --target=cleanup --all", + "build": "nx run-many --target=build --all", + "build:affected": "nx affected --target=build", + "lint": "nx run-many --target=lint --all", + "lint:fix": "nx run-many --target=lint:fix --all", + "lint:affected": "nx affected --target=lint", + "lint:staged": "npx lint-staged", + "lint:commit": "npx --no -- commitlint --edit $1", + "test": "nx run-many --target=test --all", + "test:affected": "nx affected --target=test", + "test:cov": "nx run-many --target=test:cov --all && node merge-coverage.js", + "test:cov:affected": "nx affected --target=test:cov && node merge-coverage.js", + "test:debug": "jest --logHeapUsage --detectOpenHandles--detectLeaks", + "test:log": "node --expose-gc -r tsconfig-paths/register -r ts-node/register ./node_modules/.bin/jest -w=1 --logHeapUsage --detectOpenHandles", + "test:inspect": "node --inspect-brk --expose-gc -r tsconfig-paths/register -r ts-node/register ./node_modules/.bin/jest --runInBand --logHeapUsage", + "test:coverage": "jest --ci --coverage --logHeapUsage --forceExit && node coverage-transform.js", + "scan:deps": "audit-ci --config audit-ci.json", + "scan:code": "sonarqube-verify", + "prepare": "husky" + }, "private": true, - "dependencies": {}, "devDependencies": { + "@commitlint/cli": "^17.1.2", + "@commitlint/config-conventional": "^17.1.0", + "@nestjs/schematics": "^10.0.1", + "@nestjs/testing": "^10.0.2", + "@nx/eslint": "18.2.4", + "@nx/eslint-plugin": "18.2.4", + "@nx/jest": "18.2.4", "@nx/js": "18.2.4", - "nx": "18.2.4" + "@nx/nest": "^18.2.4", + "@swc-node/register": "~1.8.0", + "@swc/core": "~1.3.85", + "@swc/helpers": "~0.5.2", + "@types/amqplib": "^0.10.5", + "@types/express": "^4.17.21", + "@types/jest": "^29.4.0", + "@types/node": "^18.16.9", + "@types/supertest": "^6.0.2", + "@types/uuid": "^9.0.8", + "@typescript-eslint/eslint-plugin": "^7.3.0", + "@typescript-eslint/parser": "^7.3.0", + "audit-ci": "^6.3.0", + "dotenv": "^16.4.5", + "eslint": "~8.57.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-import": "^2.29.0", + "eslint-plugin-max-params-no-constructor": "^0.0.4", + "eslint-plugin-simple-import-sort": "^12.0.0", + "eslint-plugin-unused-imports": "^3.1.0", + "husky": "^9.0.11", + "ioredis-mock": "^8.9.0", + "jest": "^29.4.1", + "jest-environment-node": "^29.4.1", + "lint-staged": "^15.0.3", + "mqtt": "^5.5.2", + "nx": "18.2.4", + "prettier": "^2.6.2", + "supertest": "^6.3.4", + "ts-jest": "^29.1.0", + "ts-node": "10.9.1", + "typescript": "~5.4.2" + }, + "dependencies": { + "@aws-sdk/client-s3": "^3.554.0", + "@aws-sdk/lib-storage": "^3.554.0", + "@nestjs/common": "^10.0.2", + "@nestjs/config": "^3.2.2", + "@nestjs/core": "^10.0.2", + "@nestjs/microservices": "^10.0.2", + "@nestjs/platform-express": "^10.0.2", + "amqp-connection-manager": "^4.1.14", + "amqplib": "^0.10.4", + "ioredis": "^5.3.2", + "redlock": "^5.0.0-beta.2", + "reflect-metadata": "^0.1.14", + "rxjs": "^7.8.0", + "tslib": "^2.3.0", + "uuid": "^9.0.1" }, "workspaces": [ - "packages/*" - ] + "packages/**" + ], + "lint-staged": { + "*.{ts,tsx}": [ + "eslint" + ] + } } diff --git a/packages/amqp-transport/.eslintrc.json b/packages/amqp-transport/.eslintrc.json new file mode 100644 index 0000000..69704e6 --- /dev/null +++ b/packages/amqp-transport/.eslintrc.json @@ -0,0 +1,33 @@ +{ + "extends": ["../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.json"], + "parser": "jsonc-eslint-parser", + "rules": { + "@nx/dependency-checks": [ + "error", + { + "buildTargets": ["build"], + "checkMissingDependencies": true, + "checkObsoleteDependencies": true, + "checkVersionMismatches": true + } + ] + } + } + ] +} diff --git a/packages/amqp-transport/CHANGELOG.md b/packages/amqp-transport/CHANGELOG.md new file mode 100644 index 0000000..13d42d2 --- /dev/null +++ b/packages/amqp-transport/CHANGELOG.md @@ -0,0 +1,102 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.5.1](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-amqp-transport@0.5.0...@s1seven/nestjs-tools-amqp-transport@0.5.1) (2023-09-04) + +**Note:** Version bump only for package @s1seven/nestjs-tools-amqp-transport + +# [0.5.0](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-amqp-transport@0.4.3...@s1seven/nestjs-tools-amqp-transport@0.5.0) (2023-01-05) + +### Bug Fixes + +- **amqp-transport:** wait for channel to be connected to set reply queue consumer ([d8346d3](https://github.com/s1seven/nestjs-tools/commit/d8346d3f7cea197251f49e203c2e90dbad3214c8)) + +### Features + +- **amqp-transport:** add options to selectively enable amqp assertions ([b8b36c6](https://github.com/s1seven/nestjs-tools/commit/b8b36c6a15886e5a736649f2e0211051e2c88f5d)) + +## [0.4.3](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-amqp-transport@0.4.2...@s1seven/nestjs-tools-amqp-transport@0.4.3) (2022-12-21) + +**Note:** Version bump only for package @s1seven/nestjs-tools-amqp-transport + +## [0.4.2](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-amqp-transport@0.4.1...@s1seven/nestjs-tools-amqp-transport@0.4.2) (2022-12-07) + +### Bug Fixes + +- **amqp-transport:** set proper types for AmqpOptions.socketOptions ([f57a0d1](https://github.com/s1seven/nestjs-tools/commit/f57a0d152421347d3fa23f6f4b72792cc18a0f2e)) + +## [0.4.1](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-amqp-transport@0.4.0...@s1seven/nestjs-tools-amqp-transport@0.4.1) (2022-11-30) + +### Bug Fixes + +- **amqp-transport:** improve channel and reply queue handling in producer ([717c08d](https://github.com/s1seven/nestjs-tools/commit/717c08d70d99326d6893635de47d9c9d622229ff)) +- **amqp-transport:** improve channel error handling in consumer ([e0eb127](https://github.com/s1seven/nestjs-tools/commit/e0eb127d0319c8259d46177860b4ddbf3068ce24)) +- **amqp-transport:** wait for channel readiness ([b43a667](https://github.com/s1seven/nestjs-tools/commit/b43a667a853a9ebed75e80549fd2b24d2a9889ab)) + +# [0.4.0](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-amqp-transport@0.3.2...@s1seven/nestjs-tools-amqp-transport@0.4.0) (2022-09-14) + +### Bug Fixes + +- **amqp-transport:** handle channel setup errors ([cafa1df](https://github.com/s1seven/nestjs-tools/commit/cafa1df5492e18b97c9333b8955c9fe06ff8df70)) + +### Features + +- **amqp-transport:** apply latest changes from NestJS RMQ ([357bb9e](https://github.com/s1seven/nestjs-tools/commit/357bb9ee369d3849666e627da01c48a1134e03b0)) + +## [0.3.2](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-amqp-transport@0.3.1...@s1seven/nestjs-tools-amqp-transport@0.3.2) (2022-08-09) + +**Note:** Version bump only for package @s1seven/nestjs-tools-amqp-transport + +## [0.3.1](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-amqp-transport@0.3.0...@s1seven/nestjs-tools-amqp-transport@0.3.1) (2022-08-03) + +### Bug Fixes + +- **amqp-transport:** add missing callback ([036c1e6](https://github.com/s1seven/nestjs-tools/commit/036c1e6a50e5abc3602d94d6a907399d4364c10c)) + +# [0.3.0](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-amqp-transport@0.2.2...@s1seven/nestjs-tools-amqp-transport@0.3.0) (2022-06-14) + +### Bug Fixes + +- **amqp-transport:** improve message and errors handling ([db8d334](https://github.com/s1seven/nestjs-tools/commit/db8d33497d6c54f04ab16657bd1f0ab2bbf38ac5)) + +### Features + +- **amqp-transport:** add AMQP record serializer ([edc4b7e](https://github.com/s1seven/nestjs-tools/commit/edc4b7eec751145c989ef4e2321e29f6c8dd45d9)) + +## [0.2.2](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-amqp-transport@0.2.1...@s1seven/nestjs-tools-amqp-transport@0.2.2) (2022-06-02) + +**Note:** Version bump only for package @s1seven/nestjs-tools-amqp-transport + +## 0.2.1 (2022-03-17) + +**Note:** Version bump only for package @s1seven/nestjs-tools-amqp-transport + +# [0.2.0](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-amqp-transport@0.1.3...@s1seven/microservices-amqp-transport@0.2.0) (2022-02-10) + +### Features + +- **amqp-transport:** integrate new `connectFailed` event ([37a7fcb](https://github.com/s1seven/microservices-common/commit/37a7fcba2f31a97aeeffd630aff497d8e9e68ef2)) + +## [0.1.3](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-amqp-transport@0.1.2...@s1seven/microservices-amqp-transport@0.1.3) (2021-11-22) + +**Note:** Version bump only for package @s1seven/microservices-amqp-transport + +## [0.1.2](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-amqp-transport@0.1.1...@s1seven/microservices-amqp-transport@0.1.2) (2021-10-29) + +**Note:** Version bump only for package @s1seven/microservices-amqp-transport + +## [0.1.1](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-amqp-transport@0.1.0...@s1seven/microservices-amqp-transport@0.1.1) (2021-10-08) + +**Note:** Version bump only for package @s1seven/microservices-amqp-transport + +# 0.1.0 (2021-09-20) + +### Bug Fixes + +- allow deserialize to be a promise ([f958f1d](https://github.com/s1seven/microservices-common/commit/f958f1db10c2455165017c463af4d50533e09cca)) + +### Features + +- create amqp-transport package ([c26c394](https://github.com/s1seven/microservices-common/commit/c26c394512c599357f45930a8a5c6af3d17ca296)) diff --git a/packages/amqp-transport/README.md b/packages/amqp-transport/README.md new file mode 100644 index 0000000..bd3ae00 --- /dev/null +++ b/packages/amqp-transport/README.md @@ -0,0 +1,12 @@ +# AMQP-Transport + +[![npm][npm-image]][npm-url] + +[npm-image]: https://img.shields.io/npm/v/@getlarge/nestjs-tools-amqp-transport.svg?style=flat +[npm-url]: https://npmjs.org/package/@getlarge/nestjs-tools-amqp-transport + +Custom AMQP strategies for Nest microservice transport. +Supports : + +- exchanges +- assert reply queue diff --git a/packages/amqp-transport/jest.config.ts b/packages/amqp-transport/jest.config.ts new file mode 100644 index 0000000..11c9461 --- /dev/null +++ b/packages/amqp-transport/jest.config.ts @@ -0,0 +1,19 @@ +/* eslint-disable */ +export default { + displayName: 'nestjs-tools-amqp-transport', + preset: '../../jest.preset.js', + testEnvironment: 'node', + transform: { + '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }], + }, + moduleFileExtensions: ['ts', 'js', 'html'], + coverageDirectory: '../../coverage/packages/amqp-transport', + coverageThreshold: { + global: { + statements: 40, + branches: 25, + functions: 30, + lines: 40, + }, + }, +}; diff --git a/packages/amqp-transport/package.json b/packages/amqp-transport/package.json new file mode 100644 index 0000000..eec4cb8 --- /dev/null +++ b/packages/amqp-transport/package.json @@ -0,0 +1,36 @@ +{ + "name": "@getlarge/nestjs-tools-amqp-transport", + "version": "0.5.1", + "description": "Custom Nest Transport classes for AMQP", + "keywords": [ + "amqp", + "rabbitmq", + "microservices", + "nestjs" + ], + "license": "Apache-2.0", + "author": "Edouard Maleix ", + "homepage": "https://github.com/getlarge/nestjs-tools/tree/main/packages/amqp-transport", + "publishConfig": { + "registry": "https://registry.npmjs.org/" + }, + "publicConfig": { + "access": "public" + }, + "type": "commonjs", + "main": "./src/index.js", + "typings": "./src/index.d.ts", + "dependencies": { + "@getlarge/typed-event-emitter": "0.1.1", + "uuid": "^9.0.1", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@nestjs/common": "10", + "@nestjs/microservices": "10", + "amqp-connection-manager": "4", + "amqplib": "0.10", + "promise-breaker": "6.0.0", + "rxjs": "7" + } +} diff --git a/packages/amqp-transport/project.json b/packages/amqp-transport/project.json new file mode 100644 index 0000000..a8a2d1e --- /dev/null +++ b/packages/amqp-transport/project.json @@ -0,0 +1,20 @@ +{ + "name": "nestjs-tools-amqp-transport", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "packages/amqp-transport/src", + "projectType": "library", + "tags": [], + "targets": { + "build": { + "executor": "@nx/js:tsc", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/packages/amqp-transport", + "tsConfig": "packages/amqp-transport/tsconfig.lib.json", + "packageJson": "packages/amqp-transport/package.json", + "main": "packages/amqp-transport/src/index.ts", + "assets": ["packages/amqp-transport/*.md"] + } + } + } +} diff --git a/packages/amqp-transport/src/index.ts b/packages/amqp-transport/src/index.ts new file mode 100644 index 0000000..4776c50 --- /dev/null +++ b/packages/amqp-transport/src/index.ts @@ -0,0 +1,4 @@ +export * from './lib/amqp.constants'; +export * from './lib/amqp.interfaces'; +export * from './lib/amqp-client'; +export * from './lib/amqp-server'; diff --git a/packages/amqp-transport/src/lib/amqp-client.ts b/packages/amqp-transport/src/lib/amqp-client.ts new file mode 100644 index 0000000..6880463 --- /dev/null +++ b/packages/amqp-transport/src/lib/amqp-client.ts @@ -0,0 +1,343 @@ +import { EventHandlers, TypedEventEmitter } from '@getlarge/typed-event-emitter'; +import { Logger } from '@nestjs/common/services/logger.service'; +import { + ClientProxy, + type ReadPacket, + type RmqRecord, + type RmqRecordOptions, + type WritePacket, +} from '@nestjs/microservices'; +import { + CONNECT_EVENT, + DISCONNECT_EVENT, + DISCONNECTED_RMQ_MESSAGE, + ERROR_EVENT, + RQM_DEFAULT_NO_ASSERT, + RQM_DEFAULT_NOACK, + RQM_DEFAULT_PERSISTENT, + RQM_DEFAULT_PREFETCH_COUNT, + RQM_DEFAULT_QUEUE_OPTIONS, + RQM_DEFAULT_URL, +} from '@nestjs/microservices/constants'; +import type { RmqUrl } from '@nestjs/microservices/external/rmq-url.interface'; +import { AmqpConnectionManager, Channel, ChannelWrapper, connect } from 'amqp-connection-manager'; +import { Connection, ConsumeMessage, Options } from 'amqplib'; +import type PromiseBreaker from 'promise-breaker'; +import { EmptyError, firstValueFrom, fromEvent, merge, Observable, ReplaySubject } from 'rxjs'; +import { first, map, retryWhen, scan, skip, switchMap } from 'rxjs/operators'; +import { v4 as uuid } from 'uuid'; + +import { + AMQP_DEFAULT_EXCHANGE_OPTIONS, + AMQP_DEFAULT_EXCHANGE_TYPE, + CONNECT_FAILED_EVENT, + CONNECT_FAILED_EVENT_MSG, +} from './amqp.constants'; +import { AmqpOptions } from './amqp.interfaces'; +import { AmqpRecordSerializer } from './amqp-record.serializer'; + +export interface ConsumeMessageEvent extends EventHandlers { + [correlationId: string]: (msg: ConsumeMessage) => Promise | void; +} + +export class AmqpClient extends ClientProxy { + protected readonly logger = new Logger(ClientProxy.name); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + protected connection$!: ReplaySubject; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + protected connection!: Promise; + protected client: AmqpConnectionManager | null = null; + protected channel: ChannelWrapper | null = null; + protected urls: string[] | RmqUrl[]; + protected queue?: string; + protected queueOptions: Options.AssertQueue; + protected replyQueue: string; + protected replyQueueOptions: Options.AssertQueue; + protected persistent: boolean; + protected exchange?: string; + protected exchangeType: string; + protected exchangeOptions?: Options.AssertExchange; + protected prefetchCount: number; + protected noAssert: boolean; + protected noQueueAssert: boolean; + protected noReplyQueueAssert: boolean; + protected noExchangeAssert: boolean; + protected responseEmitter!: TypedEventEmitter; + + constructor(protected readonly options: AmqpOptions) { + super(); + this.urls = this.getOptionsProp(this.options, 'urls') || [RQM_DEFAULT_URL]; + this.queue = this.getOptionsProp(this.options, 'queue') || undefined; + this.queueOptions = this.getOptionsProp(this.options, 'queueOptions') || RQM_DEFAULT_QUEUE_OPTIONS; + this.replyQueue = this.getOptionsProp(this.options, 'replyQueue') || ''; + //? use RMQ_DEFAULT_REPLY_QUEUE_OPTIONS + this.replyQueueOptions = this.getOptionsProp(this.options, 'replyQueueOptions') || RQM_DEFAULT_QUEUE_OPTIONS; + this.persistent = this.getOptionsProp(this.options, 'persistent') || RQM_DEFAULT_PERSISTENT; + this.exchange = this.getOptionsProp(this.options, 'exchange') || undefined; + this.exchangeType = this.getOptionsProp(this.options, 'exchangeType') || AMQP_DEFAULT_EXCHANGE_TYPE; + this.exchangeOptions = this.getOptionsProp(this.options, 'exchangeOptions') || AMQP_DEFAULT_EXCHANGE_OPTIONS; + this.prefetchCount = this.getOptionsProp(this.options, 'prefetchCount') || RQM_DEFAULT_PREFETCH_COUNT; + this.noAssert = this.getOptionsProp(this.options, 'noAssert') || RQM_DEFAULT_NO_ASSERT; + this.noQueueAssert = this.getOptionsProp(this.options, 'noQueueAssert') || RQM_DEFAULT_NO_ASSERT; + this.noReplyQueueAssert = this.getOptionsProp(this.options, 'noReplyQueueAssert') || RQM_DEFAULT_NO_ASSERT; + this.noExchangeAssert = this.getOptionsProp(this.options, 'noExchangeAssert') || RQM_DEFAULT_NO_ASSERT; + this.initializeSerializer(options); + this.initializeDeserializer(options); + if (!this.queue && !this.exchange) { + throw new Error('No queue or exchange defined'); + } + } + + private get skipQueueAssert(): boolean { + return this.noAssert || this.noQueueAssert; + } + + private get skipReplyQueueAssert(): boolean { + return this.noAssert || this.noReplyQueueAssert; + } + + private get skipExchangeAssert(): boolean { + return this.noAssert || this.noExchangeAssert; + } + + close(): void { + this.channel?.close(); + this.client?.close(); + this.channel = null; + this.client = null; + } + + connect() { + if (this.client) { + return this.convertConnectionToPromise(); + } + this.client = this.createClient(); + this.handleError(this.client); + this.handleDisconnectError(this.client); + + this.responseEmitter = new TypedEventEmitter(); + this.responseEmitter.setMaxListeners(0); + + const connect$ = this.connect$(this.client); + const withDisconnect$ = this.mergeDisconnectEvent(this.client, connect$).pipe( + switchMap(() => this.createChannel()), + ); + + const withReconnect$ = fromEvent<{ connection: Connection; url: string }>( + this.client, + CONNECT_EVENT, + ({ connection, url }) => ({ + connection, + url, + }), + ).pipe(skip(1)); + const source$ = merge(withDisconnect$, withReconnect$); + + this.connection$ = new ReplaySubject(1); + source$.subscribe(this.connection$); + + return this.convertConnectionToPromise(); + } + + async convertConnectionToPromise() { + try { + return await firstValueFrom(this.connection$); + } catch (err) { + if (err instanceof EmptyError) { + return; + } + throw err; + } + } + + createClient(): AmqpConnectionManager { + const socketOptions = this.getOptionsProp(this.options, 'socketOptions'); + return connect(this.urls, { connectionOptions: socketOptions }); + } + + handleError(client: AmqpConnectionManager): void { + client.addListener(ERROR_EVENT, (err) => this.logger.error(err)); + } + + handleDisconnectError(client: AmqpConnectionManager): void { + client.addListener(DISCONNECT_EVENT, (err) => { + this.logger.error(DISCONNECTED_RMQ_MESSAGE); + this.logger.error(err.err); + this.close(); + }); + client.addListener(CONNECT_FAILED_EVENT, (err) => { + this.logger.error(CONNECT_FAILED_EVENT_MSG); + this.logger.error(err.err); + this.close(); + }); + } + + async createChannel(): Promise { + const noAck = this.getOptionsProp(this.options, 'noAck', RQM_DEFAULT_NOACK); + if (!this.client) { + throw new Error('No client found'); + } + const channel = this.client.createChannel({ + json: false, + setup: (channel: Channel) => this.setupChannel(channel), + }); + this.channel = channel; + + return new Promise((resolve, reject) => { + channel + .once('connect', () => { + // at this time `setReplyQueue` should have ben called to assert the reply queue + // if replyQueue is still undefined it means that we don't need a reply queue for this client + if (!this.replyQueue) { + return resolve(); + } + channel + .consume(this.replyQueue, (msg) => this.responseEmitter.emit(msg.properties.correlationId, msg), { + noAck, + prefetch: this.prefetchCount, + }) + .then(() => resolve()) + .catch((e) => reject(e)); + }) + .once('error', (err) => { + reject(err); + }); + }); + } + + mergeDisconnectEvent(instance: AmqpConnectionManager, source$: Observable): Observable { + const eventToError = (eventType: string) => + fromEvent(instance, eventType).pipe( + map((err) => { + throw err; + }), + ); + const disconnect$ = eventToError(DISCONNECT_EVENT); + const urls = this.getOptionsProp(this.options, 'urls', []) as string[]; + const connectFailed$ = eventToError(CONNECT_FAILED_EVENT).pipe( + retryWhen((e) => + e.pipe( + scan((errorCount, error) => { + if (urls.indexOf(error.url) >= urls.length - 1) { + throw error; + } + return errorCount + 1; + }, 0), + ), + ), + ); + return merge(source$, disconnect$, connectFailed$).pipe(first()); + } + + async setReplyQueue(channel: Channel): Promise { + if (!this.skipReplyQueueAssert) { + // autogenerate replyQueue name when it is empty and replace the property replyQueue with this name (amq.gen-****) + const q = await channel.assertQueue(this.replyQueue, this.replyQueueOptions); + this.replyQueue = q.queue; + } + } + + async setupChannel(channel: Channel): Promise { + if (this.exchange && !this.skipExchangeAssert) { + await channel.assertExchange(this.exchange, this.exchangeType, this.exchangeOptions); + } + if (typeof this.queue === 'string' && !this.skipQueueAssert) { + await channel.assertQueue(this.queue, this.queueOptions); + } + await this.setReplyQueue(channel); + } + + protected parseMessageContent(content: Buffer) { + const rawContent = content.toString(); + try { + return JSON.parse(rawContent); + } catch { + return rawContent; + } + } + + async handleMessage(msg: ConsumeMessage, callback: (packet: WritePacket) => unknown): Promise { + // TODO: retrieve deserialize options from msg + const packet = this.parseMessageContent(msg.content); + const { err, response, isDisposed } = await this.deserializer.deserialize(packet, msg.properties); + // TODO: if (this.replyQueueOptions.exclusive) { + // await this.channel.cancel(msg.fields.consumerTag); + // } + if (isDisposed || err) { + callback?.({ + err, + response, + isDisposed: true, + }); + } + callback?.({ + err, + response, + }); + } + + protected getSerializedContent(message: ReadPacket): { content: Buffer; options: RmqRecordOptions } { + const { options = {}, ...rest }: ReadPacket & Partial = this.serializer.serialize(message); + return { content: Buffer.from(JSON.stringify(rest)), options }; + } + + protected publish(message: ReadPacket, callback: (packet: WritePacket) => unknown): () => void { + try { + const correlationId: string = uuid(); + const listener = (msg: ConsumeMessage) => this.handleMessage(msg, callback); + this.responseEmitter.on(correlationId, listener); + + Object.assign(message, { id: correlationId }); + const { content, options } = this.getSerializedContent(message); + + const publishOptions: Options.Publish = { + persistent: this.persistent, + replyTo: this.replyQueue, + ...options, + headers: this.mergeHeaders(options?.headers), + correlationId, + }; + if (this.exchange) { + this.channel?.publish(this.exchange, message.pattern, content, publishOptions); + } else if (this.queue) { + this.channel?.sendToQueue(this.queue, content, publishOptions); + } + return () => this.responseEmitter.removeListener(correlationId, listener); + } catch (err) { + callback({ err }); + //? this.responseEmitter.removeListener(correlationId, listener) + return () => void 0; + } + } + protected dispatchEvent(packet: ReadPacket): Promise { + const { content, options } = this.getSerializedContent(packet); + const publishOptions: Options.Publish = { + persistent: this.persistent, + ...options, + headers: this.mergeHeaders(options?.headers), + }; + + return new Promise((resolve, reject) => { + const cb: PromiseBreaker.Callback = (err: Error | null | undefined, result: T) => + err ? reject(err) : resolve(result); + return this.exchange + ? this.channel?.publish(this.exchange, packet.pattern, content, publishOptions, cb) + : this.channel?.sendToQueue(this.queue as string, content, publishOptions, cb); + }); + } + + protected override initializeSerializer(options: AmqpOptions) { + this.serializer = options?.serializer ?? new AmqpRecordSerializer(); + } + + protected mergeHeaders(requestHeaders?: Record): Record | undefined { + if (!requestHeaders && !this.options?.headers) { + return undefined; + } + + return { + ...this.options?.headers, + ...requestHeaders, + }; + } +} diff --git a/packages/amqp-transport/src/lib/amqp-record.serializer.ts b/packages/amqp-transport/src/lib/amqp-record.serializer.ts new file mode 100644 index 0000000..553ad34 --- /dev/null +++ b/packages/amqp-transport/src/lib/amqp-record.serializer.ts @@ -0,0 +1,18 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { isObject } from '@nestjs/common/utils/shared.utils'; +import { ReadPacket, RmqRecord, Serializer } from '@nestjs/microservices'; + +export type SerializerOutput = ReadPacket & Partial>; +export class AmqpRecordSerializer implements Serializer, SerializerOutput> { + serialize(packet: ReadPacket | any): SerializerOutput { + if (packet?.data && isObject(packet.data) && packet.data instanceof RmqRecord) { + const record: RmqRecord = packet.data; + return { + ...packet, + data: record.data, + options: record.options, + }; + } + return packet; + } +} diff --git a/packages/amqp-transport/src/lib/amqp-server.ts b/packages/amqp-transport/src/lib/amqp-server.ts new file mode 100644 index 0000000..225b1b7 --- /dev/null +++ b/packages/amqp-transport/src/lib/amqp-server.ts @@ -0,0 +1,287 @@ +import { isNil, isString, isUndefined } from '@nestjs/common/utils/shared.utils'; +import { + CustomTransportStrategy, + IncomingRequest, + MessageHandler, + OutgoingResponse, + RmqContext, + Server, + Transport, +} from '@nestjs/microservices'; +import { + CONNECT_EVENT, + DISCONNECT_EVENT, + DISCONNECTED_RMQ_MESSAGE, + NO_MESSAGE_HANDLER, + RQM_DEFAULT_IS_GLOBAL_PREFETCH_COUNT, + RQM_DEFAULT_NO_ASSERT, + RQM_DEFAULT_NOACK, + RQM_DEFAULT_PREFETCH_COUNT, + RQM_DEFAULT_QUEUE_OPTIONS, + RQM_DEFAULT_URL, +} from '@nestjs/microservices/constants'; +import { RmqUrl } from '@nestjs/microservices/external/rmq-url.interface'; +import { AmqpConnectionManager, ChannelWrapper, connect } from 'amqp-connection-manager'; +import { Channel, ConsumeMessage, Options } from 'amqplib'; + +import { + AMQP_DEFAULT_EXCHANGE_OPTIONS, + AMQP_DEFAULT_EXCHANGE_TYPE, + AMQP_SEPARATOR, + CONNECT_FAILED_EVENT, + CONNECT_FAILED_EVENT_MSG, +} from './amqp.constants'; +import { AmqpOptions } from './amqp.interfaces'; +import { AmqpRecordSerializer } from './amqp-record.serializer'; + +export enum AmqpWildcard { + SINGLE_LEVEL = '*', + MULTI_LEVEL = '#', +} + +const INFINITE_CONNECTION_ATTEMPTS = -1; + +export class AmqpServer extends Server implements CustomTransportStrategy { + readonly transportId?: Transport; + private channel: ChannelWrapper | null = null; + private server: AmqpConnectionManager | null = null; + private connectionAttempts = 0; + + private urls: string[] | RmqUrl[]; + private queue: string; + private queueOptions: Options.AssertQueue; + private exchange?: string; + private exchangeType: 'direct' | 'fanout' | 'topic'; + private exchangeOptions?: Options.AssertExchange; + private prefetchCount: number; + private isGlobalPrefetchCount: boolean; + private noAssert: boolean; + private noQueueAssert: boolean; + private noExchangeAssert: boolean; + private deleteChannelOnFailure: boolean; + + constructor(private options: AmqpOptions, transportId: number | Transport = Transport.RMQ) { + super(); + this.transportId = transportId; + this.server = null; + this.channel = null; + this.urls = this.getOptionsProp(this.options, 'urls') || [RQM_DEFAULT_URL]; + this.queue = this.getOptionsProp(this.options, 'queue') || ''; + this.queueOptions = this.getOptionsProp(this.options, 'queueOptions') || RQM_DEFAULT_QUEUE_OPTIONS; + this.exchange = this.getOptionsProp(this.options, 'exchange') || undefined; + this.exchangeType = this.getOptionsProp(this.options, 'exchangeType') || AMQP_DEFAULT_EXCHANGE_TYPE; + this.exchangeOptions = this.getOptionsProp(this.options, 'exchangeOptions') || AMQP_DEFAULT_EXCHANGE_OPTIONS; + this.prefetchCount = this.getOptionsProp(this.options, 'prefetchCount') || RQM_DEFAULT_PREFETCH_COUNT; + this.isGlobalPrefetchCount = + this.getOptionsProp(this.options, 'isGlobalPrefetchCount') || RQM_DEFAULT_IS_GLOBAL_PREFETCH_COUNT; + this.noAssert = this.getOptionsProp(this.options, 'noAssert') || RQM_DEFAULT_NO_ASSERT; + this.noQueueAssert = this.getOptionsProp(this.options, 'noQueueAssert') || RQM_DEFAULT_NO_ASSERT; + this.noExchangeAssert = this.getOptionsProp(this.options, 'noExchangeAssert') || RQM_DEFAULT_NO_ASSERT; + this.deleteChannelOnFailure = this.getOptionsProp(this.options, 'deleteChannelOnFailure') || true; + + this.initializeSerializer(options); + this.initializeDeserializer(options); + } + + private get skipQueueAssert(): boolean { + return this.noAssert || this.noQueueAssert; + } + + private get skipExchangeAssert(): boolean { + return this.noAssert || this.noExchangeAssert; + } + + async listen(callback: (err?: unknown, ...optionalParams: unknown[]) => void): Promise { + try { + await this.start(callback); + } catch (err) { + callback(err); + } + } + + close(): void { + this.channel?.close(); + this.server?.close(); + this.channel = null; + this.server = null; + } + + async start(callback?: (error?: unknown) => void): Promise { + const server = this.createClient(); + this.server = server; + server.on(CONNECT_EVENT, () => { + if (this.channel) { + return; + } + this.channel = server.createChannel({ + json: false, + setup: (channel: Channel) => this.setupChannel(channel, callback), + }); + }); + + const maxConnectionAttempts = this.getOptionsProp( + this.options, + 'maxConnectionAttempts', + INFINITE_CONNECTION_ATTEMPTS, + ); + + this.server.on(DISCONNECT_EVENT, (err) => { + this.logger.error(DISCONNECTED_RMQ_MESSAGE); + this.logger.error(err); + }); + this.server.on(CONNECT_FAILED_EVENT, (error) => { + this.logger.error(CONNECT_FAILED_EVENT_MSG); + if (error['err']) { + this.logger.error(error['err']); + } + const isReconnecting = !!this.channel; + if (maxConnectionAttempts === INFINITE_CONNECTION_ATTEMPTS || isReconnecting) { + return; + } + if (++this.connectionAttempts === maxConnectionAttempts) { + this.close(); + callback?.(error['err'] ?? new Error(CONNECT_FAILED_EVENT_MSG)); + } + }); + } + + createClient(): AmqpConnectionManager { + const socketOptions = this.getOptionsProp(this.options, 'socketOptions'); + return connect(this.urls, { + connectionOptions: socketOptions, + heartbeatIntervalInSeconds: socketOptions?.heartbeatIntervalInSeconds, + reconnectTimeInSeconds: socketOptions?.reconnectTimeInSeconds, + }); + } + + async deleteChannel(channel: Channel, callback?: (error?: unknown) => void) { + try { + const { queue, exchange } = this; + if (exchange) { + await channel.deleteExchange(exchange); + await channel.deleteQueue(queue); + const registeredPatterns = [...this.messageHandlers.keys()]; + await Promise.all(registeredPatterns.map((pattern) => channel.unbindQueue(queue, exchange, pattern))); + } else { + await channel.deleteQueue(queue); + } + return true; + } catch (e) { + callback?.(e); + return false; + } + } + + async setupChannel(channel: Channel, callback?: (error?: unknown) => void, retried?: boolean): Promise { + try { + const noAck = this.getOptionsProp(this.options, 'noAck', RQM_DEFAULT_NOACK); + const { queue, exchange } = this; + if (exchange && !this.skipExchangeAssert) { + await channel.assertExchange(exchange, this.exchangeType, this.exchangeOptions); + const q = await channel.assertQueue(queue, this.queueOptions); + const registeredPatterns = [...this.messageHandlers.keys()]; + await Promise.all(registeredPatterns.map((pattern) => channel.bindQueue(q.queue, exchange, pattern))); + } else if (!this.skipQueueAssert) { + await channel.assertQueue(queue, this.queueOptions); + } + + await channel.prefetch(this.prefetchCount, this.isGlobalPrefetchCount); + channel.consume(queue, (msg) => this.handleMessage(msg, channel), { + noAck, + }); + callback?.(); + } catch (e) { + if (this.deleteChannelOnFailure) { + const deleted = await this.deleteChannel(channel, callback); + if (deleted && !retried) { + return this.setupChannel(channel, callback, true); + } + } + callback?.(e); + } + } + + matchAmqpPattern(pattern: string, topic: string): boolean { + if (!topic) { + return false; + } + const patternSegments = pattern.split(AMQP_SEPARATOR); + const topicSegments = topic.split(AMQP_SEPARATOR); + const patternSegmentsLength = patternSegments.length; + const topicSegmentsLength = topicSegments.length; + const lastIndex = patternSegmentsLength - 1; + for (const [i, currentPattern] of patternSegments.entries()) { + const patternChar = currentPattern[0]; + const currentTopic = topicSegments[i]; + if (!currentTopic && !currentPattern) { + continue; + } + if (!currentTopic && patternChar !== AmqpWildcard.MULTI_LEVEL) { + return false; + } + if (patternChar === AmqpWildcard.MULTI_LEVEL) { + return i === lastIndex; + } + if (patternChar !== AmqpWildcard.SINGLE_LEVEL && currentPattern !== currentTopic) { + return false; + } + } + return patternSegmentsLength === topicSegmentsLength; + } + + override getHandlerByPattern(pattern: string): MessageHandler | null { + const route = this.getRouteFromPattern(pattern); + if (this.messageHandlers.has(route)) { + return this.messageHandlers.get(route) || null; + } + for (const [key, value] of this.messageHandlers) { + if (key.indexOf(AmqpWildcard.SINGLE_LEVEL) === -1 && key.indexOf(AmqpWildcard.MULTI_LEVEL) === -1) { + continue; + } + if (this.matchAmqpPattern(key, route)) { + return value; + } + } + return null; + } + + async handleMessage(message: ConsumeMessage | null, channel: Channel): Promise { + if (isNil(message)) { + return; + } + const { content, properties } = message; + const rawMessage = JSON.parse(content.toString()); + const packet = await this.deserializer.deserialize(rawMessage, properties); + const pattern = isString(packet.pattern) ? packet.pattern : JSON.stringify(packet.pattern); + const rmqContext = new RmqContext([message, channel, pattern]); + if (isUndefined((packet as IncomingRequest).id)) { + return this.handleEvent(pattern, packet, rmqContext); + } + const handler = this.getHandlerByPattern(pattern); + if (!handler) { + const status = 'error'; + const noHandlerPacket: OutgoingResponse = { + id: (packet as IncomingRequest).id, + err: NO_MESSAGE_HANDLER, + status, + }; + return this.sendMessage(noHandlerPacket, properties.replyTo, properties.correlationId); + } + const response$ = this.transformToObservable(await handler(packet.data, rmqContext)); + const publish = (data: T) => this.sendMessage(data, properties.replyTo, properties.correlationId); + response$ && this.send(response$, publish); + } + + sendMessage(message: T, replyTo: string, correlationId: string): void { + const outgoingResponse = this.serializer.serialize(message as unknown as OutgoingResponse); + const options = outgoingResponse.options; + delete outgoingResponse.options; + + const buffer = Buffer.from(JSON.stringify(outgoingResponse)); + this.channel?.sendToQueue(replyTo, buffer, { correlationId, ...options }); + } + + protected override initializeSerializer(options: AmqpOptions) { + this.serializer = options?.serializer ?? new AmqpRecordSerializer(); + } +} diff --git a/packages/amqp-transport/src/lib/amqp.constants.ts b/packages/amqp-transport/src/lib/amqp.constants.ts new file mode 100644 index 0000000..416104a --- /dev/null +++ b/packages/amqp-transport/src/lib/amqp.constants.ts @@ -0,0 +1,13 @@ +export const AMQP_SEPARATOR = '.'; +export const AMQP_DEFAULT_EXCHANGE_TYPE = 'topic'; +export const AMQP_DEFAULT_EXCHANGE_OPTIONS = {}; +export const CONNECT_FAILED_EVENT = 'connectFailed'; +export const CONNECT_FAILED_EVENT_MSG = 'Failed to initialize AMQP connection'; +export const RQM_DEFAULT_DELETE_CHANNEL_ON_FAILURE = false; +export const RMQ_DEFAULT_REPLY_QUEUE_OPTIONS = { + durable: true, + /* the reply queue is named can only be used by the declaring connection */ + exclusive: true, + /* default reply queue is named โ€œโ€, so a new one will be generated at channel setup */ + autoDelete: false, +}; diff --git a/packages/amqp-transport/src/lib/amqp.interfaces.ts b/packages/amqp-transport/src/lib/amqp.interfaces.ts new file mode 100644 index 0000000..4873fdc --- /dev/null +++ b/packages/amqp-transport/src/lib/amqp.interfaces.ts @@ -0,0 +1,43 @@ +import { Deserializer, Serializer } from '@nestjs/microservices'; +import { RmqUrl } from '@nestjs/microservices/external/rmq-url.interface'; +import { Options } from 'amqplib'; +import { TcpSocketConnectOpts } from 'net'; +import { ConnectionOptions } from 'tls'; + +export interface AmqpOptions { + urls?: string[] | RmqUrl[]; + queue?: string; + queueOptions?: Options.AssertQueue; + prefetchCount?: number; + isGlobalPrefetchCount?: boolean; + maxConnectionAttempts?: number; + persistent?: boolean; + replyQueue?: string; + replyQueueOptions?: Options.AssertQueue; + exchange?: string; + exchangeType?: 'direct' | 'fanout' | 'topic'; + exchangeOptions?: Options.AssertExchange; + noAck?: boolean; + noAssert?: boolean; + noQueueAssert?: boolean; + noReplyQueueAssert?: boolean; + noExchangeAssert?: boolean; + deleteChannelOnFailure?: boolean; + socketOptions?: (ConnectionOptions | TcpSocketConnectOpts) & { + noDelay?: boolean; + timeout?: number; + keepAlive?: boolean; + keepAliveDelay?: number; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + clientProperties?: any; + credentials?: { + mechanism: string; + username: string; + password: string; + response: () => Buffer; + }; + } & { heartbeatIntervalInSeconds: number; reconnectTimeInSeconds: number }; + serializer?: Serializer; + deserializer?: Deserializer; + headers?: Record; +} diff --git a/packages/amqp-transport/test/README.md b/packages/amqp-transport/test/README.md new file mode 100644 index 0000000..e69de29 diff --git a/packages/amqp-transport/test/amqp.integration.spec.ts b/packages/amqp-transport/test/amqp.integration.spec.ts new file mode 100644 index 0000000..2366ff6 --- /dev/null +++ b/packages/amqp-transport/test/amqp.integration.spec.ts @@ -0,0 +1,489 @@ +/* eslint-disable max-lines */ +/* eslint-disable max-nested-callbacks */ +/* eslint-disable max-lines-per-function */ +import { DynamicModule, INestMicroservice } from '@nestjs/common/interfaces'; +import { ClientsModule } from '@nestjs/microservices'; +import { RQM_DEFAULT_NOACK, RQM_DEFAULT_PREFETCH_COUNT } from '@nestjs/microservices/constants'; +import { Test, TestingModule } from '@nestjs/testing'; +import type { Options } from 'amqplib'; +import { setTimeout } from 'node:timers/promises'; + +import { AmqpClient, AmqpOptions, AmqpServer } from '../src'; +import { DUMMY_CLIENT, DUMMY_QUEUE, RMQ_URL } from './dummy.constants'; +import { DummyConsumerController } from './dummy-consumer.controller.mock.'; +import { DummyProducerService } from './dummy-producer.service.mock'; + +interface Closeable { + close: () => Promise; +} + +let openConnections: Closeable[] = []; + +interface BuildClientModuleOptions { + brokerUrl?: string; + prefetchCount?: number; + isGlobalPrefetchCount?: boolean; + queue?: string; + queueOptions?: Options.AssertQueue; + replyQueue?: string; + replyQueueOptions?: Options.AssertQueue; + noAck?: boolean; + url?: string; +} + +const buildClientModule = (opts: BuildClientModuleOptions = {}): DynamicModule => { + const options: AmqpOptions = { + urls: [opts.brokerUrl || RMQ_URL], + queue: opts.queue || DUMMY_QUEUE, + queueOptions: opts.queueOptions || { + durable: false, + autoDelete: true, + }, + replyQueue: opts.replyQueue || '', + replyQueueOptions: opts.replyQueueOptions || { + durable: false, + autoDelete: true, + }, + prefetchCount: opts.prefetchCount || RQM_DEFAULT_PREFETCH_COUNT, + noAck: opts.noAck ?? RQM_DEFAULT_NOACK, + }; + return ClientsModule.register([ + { + name: DUMMY_CLIENT, + customClass: AmqpClient, + options, + }, + ]); +}; + +const createNestMicroserviceOptions = (options: AmqpOptions = {}) => { + const baseOptions: AmqpOptions = { + urls: [RMQ_URL], + queue: DUMMY_QUEUE, + queueOptions: { + durable: false, + autoDelete: true, + }, + // persistent: true, + prefetchCount: RQM_DEFAULT_PREFETCH_COUNT, + noAck: RQM_DEFAULT_NOACK, + deleteChannelOnFailure: true, + ...options, + }; + return { + strategy: new AmqpServer(baseOptions), + options: baseOptions, + }; +}; + +const setupConsumer = async (testConfiguration: BuildClientModuleOptions = {}, workerId = 0) => { + const moduleConsumer = await Test.createTestingModule({ + controllers: [DummyConsumerController], + providers: [ + { + provide: 'WORKER_ID', + useValue: workerId, + }, + ], + }).compile(); + const options = createNestMicroserviceOptions(testConfiguration); + const appConsumer = moduleConsumer.createNestMicroservice(options); + await appConsumer.listen(); + openConnections.push(appConsumer); + return { moduleConsumer, appConsumer }; +}; + +const setupProducer = async (testConfiguration: BuildClientModuleOptions = {}, workerId = 0) => { + const moduleProducer = await Test.createTestingModule({ + imports: [buildClientModule(testConfiguration)], + providers: [ + DummyProducerService, + { + provide: 'WORKER_ID', + useValue: workerId, + }, + ], + }).compile(); + openConnections.push(moduleProducer); + return moduleProducer; +}; + +const makeMultipleRequests = (f: () => Promise, n: number) => { + const fns = [...Array(n)].map(() => f()); + return Promise.all(fns); +}; + +interface SetupAllOptions { + consumersCount?: number; + producersCount?: number; + testConfiguration?: BuildClientModuleOptions; +} + +const setupAll = async (options: SetupAllOptions = {}) => { + const { testConfiguration = {}, consumersCount = 1, producersCount = 1 } = options; + const consumers: { appConsumer: INestMicroservice; moduleConsumer: TestingModule }[] = []; + const producers: TestingModule[] = []; + for (let i = 0; i < producersCount; i++) { + const producer = await setupProducer(testConfiguration, i); + producers.push(producer); + } + for (let i = 0; i < consumersCount; i++) { + const consumer = await setupConsumer(testConfiguration, i); + consumers.push(consumer); + } + await setTimeout(0); + return { producers, consumers }; +}; + +const closeAll = async () => { + await Promise.all(openConnections.map((c) => c.close())); + openConnections = []; +}; + +describe('AMQP tests', () => { + const message = 'hello consumer'; + const spy = jest.spyOn(DummyConsumerController.prototype, 'emptySpy'); + + afterEach(async () => { + //! give time for messages to be published / received + spy.mockClear(); + await setTimeout(500); + await closeAll(); + }); + + it('AMQP clients should be defined', async () => { + const { + producers: [moduleProducer], + consumers: [{ moduleConsumer }], + } = await setupAll(); + + const clientProducer = moduleProducer.get(DUMMY_CLIENT); + const clientConsumer = moduleConsumer.get(DummyConsumerController); + + expect(clientProducer).toBeDefined(); + expect(clientConsumer).toBeDefined(); + }); + + it('should request response with basic configuration', async () => { + // Given + const { + producers: [moduleProducer], + } = await setupAll(); + const msg = { message }; + const service = moduleProducer.get(DummyProducerService); + + // Then + const result = await service.test(msg); + expect(result).toBeDefined(); + expect(result).toEqual(expect.objectContaining(msg)); + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith(expect.objectContaining({ data: expect.objectContaining(msg) })); + }); + + it('should request response with basic configuration multiple messages', async () => { + // Given + const { + producers: [moduleProducer], + } = await setupAll(); + const msg = { message }; + const service = moduleProducer.get(DummyProducerService); + // Then + const results = await makeMultipleRequests(() => service.test(msg), 5); + // Expect + expect(results).toBeDefined(); + expect(results.length).toBe(5); + results.forEach((r) => { + expect(r).toEqual(expect.objectContaining(msg)); + }); + expect(spy).toHaveBeenCalledTimes(results.length); + expect(spy).toHaveBeenCalledWith(expect.objectContaining({ data: expect.objectContaining(msg) })); + }); + + it('should request response with automatic ack', async () => { + // Given + const noAck = false; + const { + producers: [moduleProducer], + } = await setupAll({ testConfiguration: { noAck } }); + const msg = { message }; + const service = moduleProducer.get(DummyProducerService); + // Then + const result = await service.test(msg, noAck); + expect(result).toBeDefined(); + expect(result).toEqual(expect.objectContaining(msg)); + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith(expect.objectContaining({ data: expect.objectContaining(msg) })); + }); + + it('should request response multiple sends with automatic ack', async () => { + // Given + const noAck = false; + const { + producers: [moduleProducer], + } = await setupAll({ testConfiguration: { noAck } }); + const msg = { message }; + const service = moduleProducer.get(DummyProducerService); + // Then + const results = await makeMultipleRequests(() => service.test({ message }, noAck), 5); + // Expect + expect(results).toBeDefined(); + expect(results.length).toBe(5); + results.forEach((r) => { + expect(r).toEqual(expect.objectContaining(msg)); + }); + expect(spy).toHaveBeenCalledTimes(results.length); + expect(spy).toHaveBeenCalledWith(expect.objectContaining({ data: expect.objectContaining(msg) })); + }); + + it('should request response with manual ack', async () => { + // Given + const noAck = true; + const msg = { message }; + const { + producers: [moduleProducer], + } = await setupAll({ testConfiguration: { noAck } }); + const service = moduleProducer.get(DummyProducerService); + // Then + const result = await service.test(msg, noAck); + expect(result).toBeDefined(); + expect(result).toEqual(expect.objectContaining(msg)); + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith(expect.objectContaining({ data: expect.objectContaining(msg) })); + }); + + it('should handle multiple sends with manual ack', async () => { + // Given + const noAck = true; + const msg = { message }; + const { + producers: [moduleProducer], + } = await setupAll({ testConfiguration: { noAck } }); + const service = moduleProducer.get(DummyProducerService); + // Then + const results = await makeMultipleRequests(() => service.test(msg, noAck), 5); + // Expect + expect(results).toBeDefined(); + expect(results.length).toBe(5); + results.forEach((r) => { + expect(r).toEqual(expect.objectContaining(msg)); + }); + expect(spy).toHaveBeenCalledTimes(results.length); + expect(spy).toHaveBeenCalledWith(expect.objectContaining({ data: expect.objectContaining(msg) })); + }); + + it('should handle multiple sends with manual ack and prefetchCount set to 5', async () => { + // Given + const noAck = true; + const msg = { message }; + const { + producers: [moduleProducer], + } = await setupAll({ + testConfiguration: { noAck, prefetchCount: 5 }, + }); + const service = moduleProducer.get(DummyProducerService); + // Then + const results = await makeMultipleRequests(() => service.test(msg, noAck), 10); + // Expect + expect(results).toBeDefined(); + expect(results.length).toBe(10); + results.forEach((r) => { + expect(r).toEqual(expect.objectContaining(msg)); + }); + expect(spy).toHaveBeenCalledTimes(results.length); + expect(spy).toHaveBeenCalledWith(expect.objectContaining({ data: expect.objectContaining(msg) })); + }); + + it('should handle multiple sends with prefetch non zero and automatic ack', async () => { + // Given + const noAck = false; + const msg = { message }; + const { + producers: [moduleProducer], + } = await setupAll({ + testConfiguration: { noAck, prefetchCount: 5 }, + }); + const service = moduleProducer.get(DummyProducerService); + // Then + const result = await service.test(msg, noAck); + expect(result).toBeDefined(); + expect(result).toEqual(expect.objectContaining(msg)); + }); + + it('should handle multiple sends with prefetch and automatic ack', async () => { + // Given + const noAck = false; + const msg = { message }; + const { + producers: [moduleProducer], + } = await setupAll({ + testConfiguration: { noAck, prefetchCount: 5, isGlobalPrefetchCount: true }, + }); + const service = moduleProducer.get(DummyProducerService); + // Then + const results = await makeMultipleRequests(() => service.test(msg, noAck), 5); + // Expect + expect(results).toBeDefined(); + expect(results.length).toBe(5); + results.forEach((r) => { + expect(r).toEqual(expect.objectContaining(msg)); + }); + }); + + it('should handle multiple sends with automatic ack and message count greater than prefetchCount', async () => { + // Given + const noAck = false; + const msg = { message }; + const { + producers: [moduleProducer], + } = await setupAll({ + testConfiguration: { noAck, prefetchCount: 5, isGlobalPrefetchCount: true }, + }); + const service = moduleProducer.get(DummyProducerService); + // Then + const results = await makeMultipleRequests(() => service.test(msg, noAck), 5); + // Expect + expect(results).toBeDefined(); + results.forEach((r) => { + expect(r).toEqual(expect.objectContaining(msg)); + }); + }); + + it('should spread load on 2 consumers with prefetch set to 1 and manual ack', async () => { + // Given + const noAck = true; + const { + producers: [moduleProducer], + } = await setupAll({ + testConfiguration: { noAck, prefetchCount: 1 }, + consumersCount: 2, + }); + const service = moduleProducer.get(DummyProducerService); + // Then + const results = await makeMultipleRequests(() => service.getConsumerWorkerId(noAck), 20); + // Expect + expect(results).toBeDefined(); + expect(spy).toHaveBeenCalledWith(expect.objectContaining({ workerId: 0 })); + expect(spy).toHaveBeenCalledWith(expect.objectContaining({ workerId: 1 })); + }); + + it('should respond to the right producer with prefetch set to 1 and manual ack', async () => { + // Given + const noAck = true; + const msg = { message }; + const { + producers: [moduleProducer1, moduleProducer2], + } = await setupAll({ + testConfiguration: { noAck, prefetchCount: 1 }, + producersCount: 2, + }); + const service1 = moduleProducer1.get(DummyProducerService); + const service2 = moduleProducer2.get(DummyProducerService); + // Then + const resultsMatrix = await Promise.all([ + makeMultipleRequests(() => service1.test(msg, noAck), 10), + makeMultipleRequests(() => service2.test(msg, noAck), 10), + ]); + // Expect + expect(resultsMatrix.length).toBe(2); + expect(resultsMatrix[0].length).toBe(10); + expect(resultsMatrix[1].length).toBe(10); + resultsMatrix[0].forEach((r) => { + expect(r).toHaveProperty('producerId'); + expect(r.producerId).toEqual(0); + }); + resultsMatrix[1].forEach((r) => { + expect(r).toHaveProperty('producerId'); + expect(r.producerId).toEqual(1); + }); + }); + + it('should respond to the right producer with prefetch set to 1, exclusive reply queue and manual ack', async () => { + // Given + const noAck = true; + const msg = { message }; + const { + producers: [moduleProducer1, moduleProducer2], + } = await setupAll({ + testConfiguration: { + noAck, + prefetchCount: 1, + replyQueueOptions: { exclusive: true, autoDelete: true, durable: false }, + }, + producersCount: 2, + }); + const service1 = moduleProducer1.get(DummyProducerService); + const service2 = moduleProducer2.get(DummyProducerService); + // Then + const resultsMatrix = await Promise.all([ + makeMultipleRequests(() => service1.test(msg, noAck), 10), + makeMultipleRequests(() => service2.test(msg, noAck), 10), + ]); + // Expect + expect(resultsMatrix.length).toBe(2); + expect(resultsMatrix[0].length).toBe(10); + expect(resultsMatrix[1].length).toBe(10); + resultsMatrix[0].forEach((r) => { + expect(r).toHaveProperty('producerId'); + expect(r.producerId).toEqual(0); + }); + resultsMatrix[1].forEach((r) => { + expect(r).toHaveProperty('producerId'); + expect(r.producerId).toEqual(1); + }); + }); + + it('should reply to single producer with fixed replyQueue name ', async () => { + // Given + const noAck = true; + const msg = { message }; + const { + producers: [moduleProducer1], + } = await setupAll({ + testConfiguration: { + noAck, + prefetchCount: 1, + replyQueue: 'testingSingleQueue', + }, + producersCount: 1, + }); + const service1 = moduleProducer1.get(DummyProducerService); + // Then + const resultsMatrix = await Promise.all([makeMultipleRequests(() => service1.test(msg, noAck), 10)]); + // Expect + expect(resultsMatrix.length).toBe(1); + expect(resultsMatrix[0].length).toBe(10); + resultsMatrix[0].forEach((r) => { + expect(r).toHaveProperty('producerId'); + expect(r.producerId).toEqual(0); + }); + }); + + it('should timeout with multiple producer with identical replyQueue name', async () => { + // Given + const noAck = true; + const msg = { message }; + try { + const { + producers: [moduleProducer1, moduleProducer2], + } = await setupAll({ + testConfiguration: { + noAck, + prefetchCount: 1, + replyQueue: 'testingMultipleQueues', + }, + producersCount: 2, + }); + const service1 = moduleProducer1.get(DummyProducerService); + const service2 = moduleProducer2.get(DummyProducerService); + // Then + await Promise.all([ + makeMultipleRequests(() => service1.test(msg, noAck), 5), + makeMultipleRequests(() => service2.test(msg, noAck), 5), + ]); + } catch (ex) { + // Expect + expect(ex).toBeDefined(); + expect(ex).toEqual('TimeoutError'); + } + }, 8000); +}); diff --git a/packages/amqp-transport/test/dummy-consumer.controller.mock..ts b/packages/amqp-transport/test/dummy-consumer.controller.mock..ts new file mode 100644 index 0000000..9dabf40 --- /dev/null +++ b/packages/amqp-transport/test/dummy-consumer.controller.mock..ts @@ -0,0 +1,52 @@ +import { Controller, Inject } from '@nestjs/common/decorators'; +import { Ctx, MessagePattern, Payload, RmqContext } from '@nestjs/microservices'; +import { Channel } from 'amqp-connection-manager'; +import { Message } from 'amqplib'; + +import { + DUMMY_TOPIC_ACK, + DUMMY_TOPIC_NOACK, + DUMMY_WORKER_ID_ACK, + DUMMY_WORKER_ID_NOACK, + Resources, +} from './dummy.constants'; + +@Controller(Resources.DUMMY) +export class DummyConsumerController { + constructor(@Inject('WORKER_ID') private readonly workerId = 0) {} + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + emptySpy(args: { data: unknown; workerId?: number }) { + // leave empty we spy on this to check if controller's method is being called + } + + @MessagePattern(DUMMY_TOPIC_ACK) + identityWithAck(@Payload() data: unknown, @Ctx() context: RmqContext) { + this.emptySpy({ data, workerId: this.workerId }); + const channel = context.getChannelRef() as Channel; + const originalMessage = context.getMessage() as Message; + channel.ack(originalMessage); + return data; + } + + @MessagePattern(DUMMY_TOPIC_NOACK) + identityWithNoAck(@Payload() data: unknown) { + this.emptySpy({ data, workerId: this.workerId }); + return data; + } + + @MessagePattern(DUMMY_WORKER_ID_ACK) + getWorkerIdAck(@Payload() data: unknown, @Ctx() context: RmqContext) { + this.emptySpy({ data, workerId: this.workerId }); + const channel = context.getChannelRef() as Channel; + const originalMessage = context.getMessage() as Message; + channel.ack(originalMessage); + return { workerId: this.workerId }; + } + + @MessagePattern(DUMMY_WORKER_ID_NOACK) + workerIdNoAck(@Payload() data: unknown) { + this.emptySpy({ data, workerId: this.workerId }); + return { workerId: this.workerId }; + } +} diff --git a/packages/amqp-transport/test/dummy-producer.service.mock.ts b/packages/amqp-transport/test/dummy-producer.service.mock.ts new file mode 100644 index 0000000..8c59fbb --- /dev/null +++ b/packages/amqp-transport/test/dummy-producer.service.mock.ts @@ -0,0 +1,72 @@ +import { Inject, Injectable } from '@nestjs/common/decorators'; +import { ClientProxy } from '@nestjs/microservices'; +import { RQM_DEFAULT_NOACK } from '@nestjs/microservices/constants'; +import { lastValueFrom, throwError } from 'rxjs'; +import { catchError, timeout } from 'rxjs/operators'; + +import { + DUMMY_CLIENT, + DUMMY_TOPIC_ACK, + DUMMY_TOPIC_NOACK, + DUMMY_WORKER_ID_ACK, + DUMMY_WORKER_ID_NOACK, +} from './dummy.constants'; + +@Injectable() +export class DummyProducerService { + private timeToTimeout = 1500; // ms + constructor( + @Inject(DUMMY_CLIENT) private readonly client: ClientProxy, + @Inject('WORKER_ID') private readonly workerId = 0, + ) {} + + test(msg: Record, noAck = RQM_DEFAULT_NOACK) { + const topic = noAck ? DUMMY_TOPIC_NOACK : DUMMY_TOPIC_ACK; + const response$ = this.client.send(topic, { ...msg, producerId: this.workerId }).pipe( + catchError((err) => { + console.error(err); + return throwError(() => err); + }), + timeout(this.timeToTimeout), + catchError(() => { + return throwError(() => 'TimeoutError'); + }), + ); + + return lastValueFrom(response$); + } + + getConsumerWorkerId(noAck = RQM_DEFAULT_NOACK) { + const topic = noAck ? DUMMY_WORKER_ID_NOACK : DUMMY_WORKER_ID_ACK; + const response$ = this.client.send(topic, {}).pipe( + catchError((err) => { + console.error(err); + return throwError(() => err); + }), + ); + + return lastValueFrom(response$); + } + + testAck(msg: Record) { + const response$ = this.client.send(DUMMY_TOPIC_ACK, msg).pipe( + catchError((err) => { + console.error(err); + return throwError(() => err); + }), + ); + + return lastValueFrom(response$); + } + + testNoAck(msg: Record) { + const response$ = this.client.send(DUMMY_TOPIC_NOACK, msg).pipe( + catchError((err) => { + console.error(err); + return throwError(() => err); + }), + ); + + return lastValueFrom(response$); + } +} diff --git a/packages/amqp-transport/test/dummy.constants.ts b/packages/amqp-transport/test/dummy.constants.ts new file mode 100644 index 0000000..07fa9b2 --- /dev/null +++ b/packages/amqp-transport/test/dummy.constants.ts @@ -0,0 +1,13 @@ +export enum Resources { + DUMMY = 'dummy', +} +export const DUMMY_QUEUE = 'testing'; +export const DUMMY_REPLY_QUEUE = 'testing_reply'; +export const DUMMY_TOPIC_ACK = 'dummy-topic-ack'; +export const DUMMY_TOPIC_NOACK = 'dummy-topic-noack'; +export const DUMMY_WORKER_ID_ACK = 'dummy-worker-id-ack'; +export const DUMMY_WORKER_ID_NOACK = 'dummy-worker-id-ack'; + +export const DUMMY_CLIENT = 'DUMMY_CLIENT'; + +export const RMQ_URL = process.env['BROKER_URL'] || 'amqp://guest:guest@localhost:5672'; diff --git a/packages/amqp-transport/tsconfig.json b/packages/amqp-transport/tsconfig.json new file mode 100644 index 0000000..15fd751 --- /dev/null +++ b/packages/amqp-transport/tsconfig.json @@ -0,0 +1,23 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "module": "commonjs", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "emitDecoratorMetadata": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/packages/amqp-transport/tsconfig.lib.json b/packages/amqp-transport/tsconfig.lib.json new file mode 100644 index 0000000..d85850b --- /dev/null +++ b/packages/amqp-transport/tsconfig.lib.json @@ -0,0 +1,16 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "declaration": true, + "types": ["node"], + "target": "es2021", + "strictNullChecks": true, + "noImplicitAny": true, + "strictBindCallApply": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src/**/*.ts"], + "exclude": ["jest.config.ts", "src/**/*.mock.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] +} diff --git a/packages/amqp-transport/tsconfig.spec.json b/packages/amqp-transport/tsconfig.spec.json new file mode 100644 index 0000000..8c8a094 --- /dev/null +++ b/packages/amqp-transport/tsconfig.spec.json @@ -0,0 +1,18 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "emitDecoratorMetadata": true, + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "jest.config.ts", + "src/**/*.mock.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts", + "test/**/*.mock.ts", + "test/**/*.spec.ts" + ] +} diff --git a/packages/async-local-storage/.eslintrc.json b/packages/async-local-storage/.eslintrc.json new file mode 100644 index 0000000..69704e6 --- /dev/null +++ b/packages/async-local-storage/.eslintrc.json @@ -0,0 +1,33 @@ +{ + "extends": ["../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.json"], + "parser": "jsonc-eslint-parser", + "rules": { + "@nx/dependency-checks": [ + "error", + { + "buildTargets": ["build"], + "checkMissingDependencies": true, + "checkObsoleteDependencies": true, + "checkVersionMismatches": true + } + ] + } + } + ] +} diff --git a/packages/async-local-storage/CHANGELOG.md b/packages/async-local-storage/CHANGELOG.md new file mode 100644 index 0000000..e46e0ea --- /dev/null +++ b/packages/async-local-storage/CHANGELOG.md @@ -0,0 +1,32 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.2.2](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-async-local-storage@0.2.1...@s1seven/nestjs-tools-async-local-storage@0.2.2) (2023-09-04) + +**Note:** Version bump only for package @s1seven/nestjs-tools-async-local-storage + +## [0.2.1](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-async-local-storage@0.2.0...@s1seven/nestjs-tools-async-local-storage@0.2.1) (2023-02-06) + +### Bug Fixes + +- **async-local-storage:** make access to `AsyncLocalStorageService` static methods safe ([30c0770](https://github.com/s1seven/nestjs-tools/commit/30c07707945eaa06d45aa1d56c4cdf76b1fd5e19)) + +# [0.2.0](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-async-local-storage@0.1.0...@s1seven/nestjs-tools-async-local-storage@0.2.0) (2023-02-03) + +### Bug Fixes + +- remove default requestContext factory due to type issues ([f16b6a4](https://github.com/s1seven/nestjs-tools/commit/f16b6a40620fa2ade6ca77a11019d9f858fc1a30)) +- throw errors before creating providers ([046fd4e](https://github.com/s1seven/nestjs-tools/commit/046fd4ef641bd9711be38b5dcb8ee459c6451800)) + +### Features + +- add safety to store access via instance methods of `AsyncLocalStorageService` ([7c3db74](https://github.com/s1seven/nestjs-tools/commit/7c3db748a22fd96025b13397842a6f1bb3a3c394)) +- **async-local-storage:** extends Map in `AsyncLocalStorageService` ([dbf9863](https://github.com/s1seven/nestjs-tools/commit/dbf9863fecde46dfa374e11a875fb75d0647d4af)) + +# 0.1.0 (2023-02-02) + +### Features + +- add module implementation ([715e29d](https://github.com/s1seven/nestjs-tools/commit/715e29d6f919fe88a0896fbf9a0bb7742d94bc6c)) diff --git a/packages/async-local-storage/README.md b/packages/async-local-storage/README.md new file mode 100644 index 0000000..7551ee7 --- /dev/null +++ b/packages/async-local-storage/README.md @@ -0,0 +1,56 @@ +# Async Local Storage` + +[![npm][npm-image]][npm-url] + +[npm-image]: https://img.shields.io/npm/v/@getlarge/nestjs-tools-async-local-storage.svg?style=flat +[npm-url]: https://npmjs.org/package/@getlarge/nestjs-tools-async-local-storage + +## Installation + +```bash +$ npm install --save @getlarge/nestjs-tools-async-local-storage +``` + +## Usage + +```ts +import assert from 'assert'; +import { AsyncLocalStorage } from 'async_hooks'; + +// to provide type safety for the store map +declare module '@getlarge/nestjs-tools-async-local-storage' { + interface RequestContext { + type?: string; + } + interface ContextStoreProperties { + id: number; + username: string; + profilePicture: string; + name: string; + } +} + +import { AsyncLocalStorageService } from '@getlarge/nestjs-tools-async-local-storage'; + +const service = new AsyncLocalStorageService(new AsyncLocalStorage()); + +assert.throws(() => service.store.set('id', 1), new TypeError("Cannot read properties of undefined (reading 'set')")); +assert.throws(() => service.set('id', 1), new Error("Store is not initialized. Call 'enterWith' or 'run' first.")); + +service.enterWith(new Map()); + +// access store map directly +service.store.set('id', 1); +const id = service.store.get('id'); +assert(typeof id === 'number'); + +// access store map via service which extends Map +service.set('username', 'john'); +assert(typeof service.get('username') === 'string'); + +service.requestContext = { type: 'http' }; +const requestContext = service.requestContext; +assert(typeof requestContext.type === 'string'); + +service.delete('username'); +``` diff --git a/packages/async-local-storage/example.ts b/packages/async-local-storage/example.ts new file mode 100644 index 0000000..e27b4e1 --- /dev/null +++ b/packages/async-local-storage/example.ts @@ -0,0 +1,39 @@ +/* run with npx ts-node packages/async-local-storage/example.ts */ +import assert from 'assert'; +import { AsyncLocalStorage } from 'async_hooks'; + +declare module './src' { + interface RequestContext { + type?: string; + } + interface ContextStoreProperties { + id: number; + username: string; + profilePicture: string; + name: string; + } +} + +import { AsyncLocalStorageService } from './src'; + +const service = new AsyncLocalStorageService(new AsyncLocalStorage()); + +assert.throws(() => service.store.set('id', 1), new TypeError("Cannot read properties of undefined (reading 'set')")); +assert.throws(() => service.set('id', 1), new Error("Store is not initialized. Call 'enterWith' or 'run' first.")); + +service.enterWith(new Map()); + +// access store map directly +service.store.set('id', 1); +const id = service.store.get('id'); +assert(typeof id === 'number'); + +// access store map via service which extends Map +service.set('username', 'john'); +assert(typeof service.get('username') === 'string'); + +service.requestContext = { type: 'http' }; +const requestContext = service.requestContext; +assert(typeof requestContext.type === 'string'); + +service.delete('username'); diff --git a/packages/async-local-storage/jest.config.ts b/packages/async-local-storage/jest.config.ts new file mode 100644 index 0000000..31a17c2 --- /dev/null +++ b/packages/async-local-storage/jest.config.ts @@ -0,0 +1,19 @@ +/* eslint-disable */ +export default { + displayName: 'nestjs-tools-async-local-storage', + preset: '../../jest.preset.js', + testEnvironment: 'node', + transform: { + '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }], + }, + moduleFileExtensions: ['ts', 'js', 'html'], + coverageDirectory: '../../coverage/packages/async-local-storage', + coverageThreshold: { + global: { + statements: 40, + branches: 25, + functions: 30, + lines: 40, + }, + }, +}; diff --git a/packages/async-local-storage/package.json b/packages/async-local-storage/package.json new file mode 100644 index 0000000..9488f67 --- /dev/null +++ b/packages/async-local-storage/package.json @@ -0,0 +1,28 @@ +{ + "name": "@getlarge/nestjs-tools-async-local-storage", + "version": "0.2.2", + "description": "Node Async Hooks wrapper to store request context", + "keywords": [ + "node", + "async hooks", + "request context", + "nestjs" + ], + "license": "Apache-2.0", + "author": "Edouard Maleix ", + "homepage": "https://github.com/getlarge/nestjs-tools/tree/main/packages/async-local-storage", + "publishConfig": { + "registry": "https://registry.npmjs.org/" + }, + "publicConfig": { + "access": "public" + }, + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@nestjs/common": "10", + "@nestjs/core": "10", + "rxjs": "^7.8.0" + } +} diff --git a/packages/async-local-storage/project.json b/packages/async-local-storage/project.json new file mode 100644 index 0000000..315ec9b --- /dev/null +++ b/packages/async-local-storage/project.json @@ -0,0 +1,20 @@ +{ + "name": "nestjs-tools-async-local-storage", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "packages/async-local-storage/src", + "projectType": "library", + "tags": [], + "targets": { + "build": { + "executor": "@nx/js:tsc", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/packages/async-local-storage", + "tsConfig": "packages/async-local-storage/tsconfig.lib.json", + "packageJson": "packages/async-local-storage/package.json", + "main": "packages/async-local-storage/src/index.ts", + "assets": ["packages/async-local-storage/*.md"] + } + } + } +} diff --git a/packages/async-local-storage/src/index.ts b/packages/async-local-storage/src/index.ts new file mode 100644 index 0000000..2d390e5 --- /dev/null +++ b/packages/async-local-storage/src/index.ts @@ -0,0 +1,7 @@ +export * from './lib/async-local-storage.constants'; +export * from './lib/async-local-storage.guard'; +export * from './lib/async-local-storage.interceptor'; +export * from './lib/async-local-storage.interfaces'; +export * from './lib/async-local-storage.module'; +export * from './lib/async-local-storage.providers'; +export * from './lib/async-local-storage.service'; diff --git a/packages/async-local-storage/src/lib/async-local-storage.constants.ts b/packages/async-local-storage/src/lib/async-local-storage.constants.ts new file mode 100644 index 0000000..aed5b88 --- /dev/null +++ b/packages/async-local-storage/src/lib/async-local-storage.constants.ts @@ -0,0 +1,7 @@ +export const REQUEST_CONTEXT_KEY = 'ctx'; + +export const ASYNC_LOCAL_STORAGE = Symbol('AsyncLocalStorage'); +export const ASYNC_LOCAL_STORAGE_MODULE_OPTIONS = Symbol('AsyncLocalStorageModuleOptions'); + +// eslint-disable-next-line @typescript-eslint/no-empty-function +export const noOp = () => {}; diff --git a/packages/async-local-storage/src/lib/async-local-storage.guard.ts b/packages/async-local-storage/src/lib/async-local-storage.guard.ts new file mode 100644 index 0000000..ece98eb --- /dev/null +++ b/packages/async-local-storage/src/lib/async-local-storage.guard.ts @@ -0,0 +1,26 @@ +import { CanActivate, ExecutionContext, Inject, Injectable } from '@nestjs/common'; + +import { ASYNC_LOCAL_STORAGE_MODULE_OPTIONS } from './async-local-storage.constants'; +import { AsyncLocalStorageModuleOptions } from './async-local-storage.interfaces'; +import { AsyncLocalStorageService } from './async-local-storage.service'; + +/* + * This guard is used to set the request context in the AsyncLocalStorageService. + * Using a guards instead of an interceptor allows to store the request context earlier in the + * request lifecycle, which is useful for logging and tracing + */ +@Injectable() +export class AsyncLocalStorageGuard implements CanActivate { + constructor( + @Inject(AsyncLocalStorageService) + private readonly asyncLocalStorage: AsyncLocalStorageService, + @Inject(ASYNC_LOCAL_STORAGE_MODULE_OPTIONS) + private readonly options: AsyncLocalStorageModuleOptions, + ) {} + + canActivate(context: ExecutionContext): boolean { + this.asyncLocalStorage.enter(); + this.asyncLocalStorage.requestContext = this.options.requestContextFactory(context); + return true; + } +} diff --git a/packages/async-local-storage/src/lib/async-local-storage.interceptor.ts b/packages/async-local-storage/src/lib/async-local-storage.interceptor.ts new file mode 100644 index 0000000..909615e --- /dev/null +++ b/packages/async-local-storage/src/lib/async-local-storage.interceptor.ts @@ -0,0 +1,52 @@ +import { CallHandler, ExecutionContext, Inject, Injectable, NestInterceptor } from '@nestjs/common'; +import { lastValueFrom, Observable, of } from 'rxjs'; + +import { ASYNC_LOCAL_STORAGE_MODULE_OPTIONS } from './async-local-storage.constants'; +import { AsyncLocalStorageMode, AsyncLocalStorageModuleOptions } from './async-local-storage.interfaces'; +import { AsyncLocalStorageService } from './async-local-storage.service'; + +/* + * This interceptor is used to set the request context in the AsyncLocalStorageService. + * Using an interceptor instead of a guard allows to store the request context later in the request lifecycle. + * This interceptor has two modes: Guard and Interceptor. + * The Guard mode is used when the AsyncLocalStorageGuard is used. + * The Interceptor mode is used when the AsyncLocalStorageInterceptor is used. + * The Guard mode is used by default and when the ASYNC_LOCAL_STORAGE_MODE is set to Guard. + * The Interceptor mode is used when the ASYNC_LOCAL_STORAGE_MODE is set to Interceptor. + * When the Guard mode is used, the request context is set in the AsyncLocalStorageService in the AsyncLocalStorageGuard + * and the AsyncLocalStorageInterceptor is used to exit the AsyncLocalStorageService. + */ +@Injectable() +export class AsyncLocalStorageInterceptor implements NestInterceptor { + constructor( + @Inject(AsyncLocalStorageService) + private readonly asyncLocalStorage: AsyncLocalStorageService, + @Inject(ASYNC_LOCAL_STORAGE_MODULE_OPTIONS) + private readonly options: AsyncLocalStorageModuleOptions, + ) {} + + get mode(): AsyncLocalStorageMode | null { + const { useGuard, useInterceptor } = this.options; + if (useGuard) { + return AsyncLocalStorageMode.Guard; + } + if (useInterceptor) { + return AsyncLocalStorageMode.Interceptor; + } + return null; + } + + async intercept(context: ExecutionContext, next: CallHandler): Promise> { + if (this.mode === AsyncLocalStorageMode.Guard) { + const response = await lastValueFrom(next.handle()); + this.asyncLocalStorage.exit(); + return of(response); + } + const response = await this.asyncLocalStorage.instance.run(new Map(), () => { + this.asyncLocalStorage.requestContext = this.options.requestContextFactory(context); + // wait for route handler to finish its job and return the response / error + return lastValueFrom(next.handle()); + }); + return of(response); + } +} diff --git a/packages/async-local-storage/src/lib/async-local-storage.interfaces.ts b/packages/async-local-storage/src/lib/async-local-storage.interfaces.ts new file mode 100644 index 0000000..a4310e9 --- /dev/null +++ b/packages/async-local-storage/src/lib/async-local-storage.interfaces.ts @@ -0,0 +1,27 @@ +import type { ExecutionContext } from '@nestjs/common'; +import type { AsyncLocalStorage } from 'node:async_hooks'; + +import { REQUEST_CONTEXT_KEY } from './async-local-storage.constants'; + +export interface RequestContext { + [key: string]: unknown; +} + +export interface ContextStoreProperties { + [REQUEST_CONTEXT_KEY]: RequestContext; +} + +export type ContextStore = Map; + +export interface AsyncLocalStorageModuleOptions { + isGlobal?: boolean; + asyncLocalStorage?: AsyncLocalStorage>; + requestContextFactory: (ctx: ExecutionContext) => RequestContext; + useGuard?: boolean; + useInterceptor?: boolean; +} + +export enum AsyncLocalStorageMode { + Guard = 'guard', + Interceptor = 'interceptor', +} diff --git a/packages/async-local-storage/src/lib/async-local-storage.module.ts b/packages/async-local-storage/src/lib/async-local-storage.module.ts new file mode 100644 index 0000000..a6612d1 --- /dev/null +++ b/packages/async-local-storage/src/lib/async-local-storage.module.ts @@ -0,0 +1,49 @@ +import { DynamicModule, Module } from '@nestjs/common'; +import { APP_GUARD, APP_INTERCEPTOR } from '@nestjs/core'; + +import { AsyncLocalStorageGuard } from './async-local-storage.guard'; +import { AsyncLocalStorageInterceptor } from './async-local-storage.interceptor'; +import { AsyncLocalStorageModuleOptions } from './async-local-storage.interfaces'; +import { createAsyncLocalStorageProviders } from './async-local-storage.providers'; + +@Module({}) +export class AsyncLocalStorageModule { + public static forRoot(options: AsyncLocalStorageModuleOptions): DynamicModule { + const { isGlobal, useGuard, useInterceptor } = options; + if (!options.requestContextFactory) { + throw new Error('`requestContextFactory` is required.'); + } + if (useGuard && useInterceptor) { + throw new Error("Can't use both guard and interceptor."); + } + const providers = createAsyncLocalStorageProviders(options); + return { + global: isGlobal, + module: AsyncLocalStorageModule, + providers: [ + ...providers, + ...(useGuard + ? [ + { + provide: APP_GUARD, + useClass: AsyncLocalStorageGuard, + }, + { + provide: APP_INTERCEPTOR, + useClass: AsyncLocalStorageInterceptor, + }, + ] + : []), + ...(useInterceptor + ? [ + { + provide: APP_INTERCEPTOR, + useClass: AsyncLocalStorageInterceptor, + }, + ] + : []), + ], + exports: providers, + }; + } +} diff --git a/packages/async-local-storage/src/lib/async-local-storage.providers.ts b/packages/async-local-storage/src/lib/async-local-storage.providers.ts new file mode 100644 index 0000000..f5c840a --- /dev/null +++ b/packages/async-local-storage/src/lib/async-local-storage.providers.ts @@ -0,0 +1,37 @@ +import type { Provider } from '@nestjs/common'; +import { AsyncLocalStorage } from 'node:async_hooks'; + +import { ASYNC_LOCAL_STORAGE, ASYNC_LOCAL_STORAGE_MODULE_OPTIONS } from './async-local-storage.constants'; +import { AsyncLocalStorageModuleOptions, ContextStoreProperties } from './async-local-storage.interfaces'; +import { AsyncLocalStorageService } from './async-local-storage.service'; + +type K = keyof ContextStoreProperties; +type T = ContextStoreProperties; +type StoreMap = Map; + +const defaultAsyncLocalStorage = (): AsyncLocalStorage => new AsyncLocalStorage(); + +export function createAsyncLocalStorageProviders( + options: AsyncLocalStorageModuleOptions, +): [ + Provider>, + Provider, + Provider, +] { + const { asyncLocalStorage = defaultAsyncLocalStorage() } = options; + const opts = { ...options, asyncLocalStorage }; + return [ + { provide: ASYNC_LOCAL_STORAGE, useValue: asyncLocalStorage }, + { + provide: ASYNC_LOCAL_STORAGE_MODULE_OPTIONS, + useValue: opts, + }, + { + provide: AsyncLocalStorageService, + inject: [ASYNC_LOCAL_STORAGE], + useFactory(store: AsyncLocalStorage) { + return new AsyncLocalStorageService(store); + }, + }, + ]; +} diff --git a/packages/async-local-storage/src/lib/async-local-storage.service.ts b/packages/async-local-storage/src/lib/async-local-storage.service.ts new file mode 100644 index 0000000..f66146d --- /dev/null +++ b/packages/async-local-storage/src/lib/async-local-storage.service.ts @@ -0,0 +1,182 @@ +import { Inject, Injectable } from '@nestjs/common'; +import type { AsyncLocalStorage } from 'node:async_hooks'; + +import { ASYNC_LOCAL_STORAGE, noOp, REQUEST_CONTEXT_KEY } from './async-local-storage.constants'; +import { ContextStoreProperties } from './async-local-storage.interfaces'; + +type K = keyof ContextStoreProperties; +type T = ContextStoreProperties; + +/** + * @description Define the type of the store + * Declared this way to share same type between the static methods and the instance methods + * This can be done with a generic type but it's not possible to use the generic type in the static methods + * It can be customized by merging ContextStoreProperties and RequestContext interface in your own declaration file + */ +export type StoreMap = Map; + +/** + * @description Provide methods to manipulate the AsyncLocalStorage store + * It holds a shared reference to the AsyncLocalStorage instance that can be accessed through the static and instance methods + * static methods are used to manipulate the global store without having to inject the service + * instance methods are used to manipulate the store + * instance methods extending the Map class are available once the store is initialized with enterWith or run + * @example + * declare module '@getlarge/nestjs-tools-async-local-storage' { + * interface RequestContext { + * type: string; + * } + * interface ContextStoreProperties { + * id: number; + * username: string; + * } + * } + * import assert from 'assert'; + * import { AsyncLocalStorage } from 'async_hooks'; + * import { AsyncLocalStorageService } from '@getlarge/nestjs-tools-async-local-storage'; + * + * const service = new AsyncLocalStorageService(new AsyncLocalStorage()); + * service.enterWith(new Map()); + * service.set('id', 1); + * const id = service.get('id'); + * assert(typeof id === 'number'); + * + * service.requestContext = { type: 'http' }; + * const requestContext = service.requestContext; + * assert(typeof requestContext.type === 'string'); + */ +@Injectable() +export class AsyncLocalStorageService extends Map { + readonly instance: AsyncLocalStorage; + private static _instance: AsyncLocalStorage; + + constructor(@Inject(ASYNC_LOCAL_STORAGE) instance: AsyncLocalStorage) { + super(); + // ensure that AsyncLocalStorageService is a singleton + AsyncLocalStorageService.instance ??= instance; + this.instance = AsyncLocalStorageService.instance || instance; + } + + static get instance(): AsyncLocalStorage { + return this._instance; + } + + static set instance(value: AsyncLocalStorage) { + this._instance = value; + } + + static get store() { + return this.instance?.getStore(); + } + + static get requestContext(): T[typeof REQUEST_CONTEXT_KEY] { + return this.store?.get(REQUEST_CONTEXT_KEY) as T[typeof REQUEST_CONTEXT_KEY]; + } + + static set requestContext(value: T[typeof REQUEST_CONTEXT_KEY]) { + this.store?.set(REQUEST_CONTEXT_KEY, value); + } + + static enterWith(value: StoreMap = new Map()): void { + this.instance?.enterWith(value); + } + + static enter(): void { + this.enterWith(); + } + + static exit(cb: () => void = noOp): void { + this.instance?.exit(cb); + } + + // AsyncLocalStorage methods and properties + run(store: StoreMap, callback: (...args: TArgs) => R, ...args: TArgs): R { + return this.instance.run(store, callback, ...args); + } + + enterWith(value: StoreMap = new Map()): void { + this.instance.enterWith(value); + } + + enter(): void { + this.enterWith(); + } + + exit(cb: () => void = noOp): void { + this.instance.exit(cb); + } + + get store(): StoreMap | undefined { + return this.instance.getStore(); + } + + private isStoreInitialized(x: unknown): x is StoreMap { + return !!x && typeof x === 'object' && x instanceof Map; + } + + private get safeStore(): StoreMap { + const store = this.store; + if (this.isStoreInitialized(store)) { + return store; + } + throw new Error("Store is not initialized. Call 'enterWith' or 'run' first."); + } + + // Map methods and properties + override get(key: k): T[k] | undefined { + return this.safeStore.get(key) as T[k]; + } + + override set(key: k, value: T[k]): this { + this.safeStore.set(key, value); + return this; + } + + override delete(key: K): boolean { + return this.safeStore.delete(key); + } + + override has(key: K): boolean { + return this.safeStore.has(key); + } + + override clear(): void { + return this.safeStore.clear(); + } + + override get size(): number { + return this.safeStore.size; + } + + get [Symbol.toStringTag]() { + return this.safeStore[Symbol.toStringTag]; + } + + override keys(): IterableIterator { + return this.safeStore.keys(); + } + + override values(): IterableIterator { + return this.safeStore.values(); + } + + override entries(): IterableIterator<[K, T[K]]> { + return this.safeStore.entries(); + } + + override forEach(callbackfn: (value: T[K], key: K, map: Map) => void, thisArg?: this): void { + return this.safeStore.forEach(callbackfn, thisArg); + } + + [Symbol.iterator](): IterableIterator<[K, T[K]]> { + return this.safeStore[Symbol.iterator](); + } + + get requestContext(): T[typeof REQUEST_CONTEXT_KEY] | undefined { + return this.get(REQUEST_CONTEXT_KEY); + } + + set requestContext(value: T[typeof REQUEST_CONTEXT_KEY]) { + this.set(REQUEST_CONTEXT_KEY, value); + } +} diff --git a/packages/async-local-storage/test/app.controller.mock.ts b/packages/async-local-storage/test/app.controller.mock.ts new file mode 100644 index 0000000..e767e87 --- /dev/null +++ b/packages/async-local-storage/test/app.controller.mock.ts @@ -0,0 +1,16 @@ +import { Controller, Get } from '@nestjs/common'; + +import { ExampleService } from './app.service.mock'; + +@Controller({ + path: 'Example', + version: '1', +}) +export class ExampleController { + constructor(private readonly exampleService: ExampleService) {} + + @Get() + getExample() { + return this.exampleService.getExample(); + } +} diff --git a/packages/async-local-storage/test/app.service.mock.ts b/packages/async-local-storage/test/app.service.mock.ts new file mode 100644 index 0000000..65ab989 --- /dev/null +++ b/packages/async-local-storage/test/app.service.mock.ts @@ -0,0 +1,12 @@ +import { Inject, Injectable } from '@nestjs/common'; + +import { AsyncLocalStorageService } from '../src'; + +@Injectable() +export class ExampleService { + @Inject(AsyncLocalStorageService) private readonly asyncLocalStorageService!: AsyncLocalStorageService; + + getExample() { + return this.asyncLocalStorageService.requestContext; + } +} diff --git a/packages/async-local-storage/test/async-local-storage.spec.ts b/packages/async-local-storage/test/async-local-storage.spec.ts new file mode 100644 index 0000000..2d1d9f6 --- /dev/null +++ b/packages/async-local-storage/test/async-local-storage.spec.ts @@ -0,0 +1,189 @@ +/* eslint-disable max-lines-per-function */ +import { INestApplication, Provider } from '@nestjs/common'; +import { APP_GUARD, APP_INTERCEPTOR } from '@nestjs/core'; +import { Test, TestingModule } from '@nestjs/testing'; +import { AsyncLocalStorage } from 'async_hooks'; +import * as request from 'supertest'; + +import { + AsyncLocalStorageGuard, + AsyncLocalStorageInterceptor, + AsyncLocalStorageModule, + AsyncLocalStorageModuleOptions, + AsyncLocalStorageService, +} from '../src'; +import { ExampleController } from './app.controller.mock'; +import { ExampleService } from './app.service.mock'; + +declare module '../src/lib/async-local-storage.interfaces' { + interface RequestContext { + type: string; + } +} + +const moduleFactory = async (options: AsyncLocalStorageModuleOptions, providers: Provider[] = []) => { + const module: TestingModule = await Test.createTestingModule({ + imports: [AsyncLocalStorageModule.forRoot(options)], + providers: [ExampleService, ...providers], + controllers: [ExampleController], + }).compile(); + + return module.createNestApplication(); +}; + +describe('AsyncLocalStorageModule', () => { + let app: INestApplication; + const route = '/Example'; + const expectedResponse = { type: 'http' }; + + afterEach(() => { + return app?.close(); + }); + + it('should provide request context when using explicit guard', async () => { + app = await moduleFactory( + { + isGlobal: true, + requestContextFactory: (ctx) => ({ type: ctx.getType() }), + }, + [{ provide: APP_GUARD, useClass: AsyncLocalStorageGuard }], + ).then((app) => app.init()); + // + const { body } = await request(app.getHttpServer()).get(route); + expect(body).toEqual(expectedResponse); + }); + + it('should provide request context when using implicit guard', async () => { + app = await moduleFactory({ + isGlobal: true, + requestContextFactory: (ctx) => ({ type: ctx.getType() }), + useGuard: true, + }).then((app) => app.init()); + // + const { body } = await request(app.getHttpServer()).get(route); + expect(body).toEqual(expectedResponse); + }); + + it('should provide request context when using explicit interceptor', async () => { + app = await moduleFactory( + { + isGlobal: true, + requestContextFactory: (ctx) => ({ type: ctx.getType() }), + }, + [{ provide: APP_INTERCEPTOR, useClass: AsyncLocalStorageInterceptor }], + ).then((app) => app.init()); + // + const { body } = await request(app.getHttpServer()).get(route); + expect(body).toEqual(expectedResponse); + }); + + it('should provide request context when using implicit interceptor', async () => { + app = await moduleFactory({ + isGlobal: true, + requestContextFactory: (ctx) => ({ type: ctx.getType() }), + useInterceptor: true, + }).then((app) => app.init()); + // + const { body } = await request(app.getHttpServer()).get(route); + expect(body).toEqual(expectedResponse); + }); + + it('should throw when not providing `requestContextFactory`', async () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + await expect(moduleFactory({} as any)).rejects.toThrow('`requestContextFactory` is required.'); + }); + + it('should throw when providing both useGuard and useInterceptor', async () => { + await expect( + moduleFactory({ + requestContextFactory: (ctx) => ({ type: ctx.getType() }), + useGuard: true, + useInterceptor: true, + }), + ).rejects.toThrow("Can't use both guard and interceptor."); + }); +}); + +describe('AsyncLocalStorageService', () => { + let service: AsyncLocalStorageService; + beforeEach(() => { + service = new AsyncLocalStorageService(new AsyncLocalStorage()); + }); + + afterEach(() => { + service?.exit(); + }); + + it('should throw when accessing store before initialization', () => { + expect(() => service.set('ctx', { type: '' })).toThrow( + "Store is not initialized. Call 'enterWith' or 'run' first.", + ); + }); + + it('should allow to set/get/delete store properties once initialized', () => { + service.enterWith(new Map()); + // + service.set('ctx', { type: '' }); + const ctx = service.get('ctx'); + expect(typeof ctx?.type).toBe('string'); + expect(typeof service.requestContext?.type).toBe('string'); + service.delete('ctx'); + expect(typeof service.requestContext).toBe('undefined'); + }); + + it('should allow to access all map properties and methods once initialized', () => { + service.enterWith(new Map()); + // + expect(service.has('ctx')).toBeFalsy(); + expect(service.size).toBe(0); + service.set('ctx', { type: '' }); + expect(service.has('ctx')).toBeTruthy(); + expect(service.size).toBe(1); + expect(Array.from(service.keys())).toEqual(['ctx']); + expect(Array.from(service.values())).toEqual([{ type: '' }]); + service.clear(); + expect(service.size).toBe(0); + }); + + it('should allow to run a function with store', () => { + service.run(new Map(), () => { + service.set('ctx', { type: '' }); + expect(service.get('ctx')).toEqual({ type: '' }); + }); + expect(service.store).toBeUndefined(); + }); + + it('should contain the same store in static and instance members', () => { + const requestContext = { type: '' }; + service.enterWith(new Map()); + service.set('ctx', requestContext); + // + expect(service.requestContext).toEqual(requestContext); + expect(service.get('ctx')).toEqual(requestContext); + expect(AsyncLocalStorageService.requestContext).toEqual(requestContext); + expect(AsyncLocalStorageService.store?.get('ctx')).toEqual(requestContext); + }); + + it('should always use a single AsyncLocalStorage reference when creating new instance', () => { + const expectedRequestContext = { type: '' }; + const newService = new AsyncLocalStorageService(new AsyncLocalStorage()); + newService.enterWith(new Map()); + newService.set('ctx', expectedRequestContext); + // + expect(AsyncLocalStorageService.instance).toBeDefined(); + expect(AsyncLocalStorageService.requestContext).toEqual(expectedRequestContext); + expect(service.requestContext).toEqual(expectedRequestContext); + expect(newService.requestContext).toEqual(expectedRequestContext); + }); + + it('should allow to access static methods without initializing the store', () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + AsyncLocalStorageService.instance = undefined as any; + // + expect(AsyncLocalStorageService.instance).toBeUndefined(); + expect(AsyncLocalStorageService.store).toBeUndefined(); + expect(() => AsyncLocalStorageService.requestContext).not.toThrow(); + expect(AsyncLocalStorageService.requestContext).toBeUndefined(); + expect(AsyncLocalStorageService.store?.has('ctx')).toBeFalsy(); + }); +}); diff --git a/packages/async-local-storage/tsconfig.json b/packages/async-local-storage/tsconfig.json new file mode 100644 index 0000000..f5b8565 --- /dev/null +++ b/packages/async-local-storage/tsconfig.json @@ -0,0 +1,22 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "module": "commonjs", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/packages/async-local-storage/tsconfig.lib.json b/packages/async-local-storage/tsconfig.lib.json new file mode 100644 index 0000000..d85850b --- /dev/null +++ b/packages/async-local-storage/tsconfig.lib.json @@ -0,0 +1,16 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "declaration": true, + "types": ["node"], + "target": "es2021", + "strictNullChecks": true, + "noImplicitAny": true, + "strictBindCallApply": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src/**/*.ts"], + "exclude": ["jest.config.ts", "src/**/*.mock.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] +} diff --git a/packages/async-local-storage/tsconfig.spec.json b/packages/async-local-storage/tsconfig.spec.json new file mode 100644 index 0000000..07412f0 --- /dev/null +++ b/packages/async-local-storage/tsconfig.spec.json @@ -0,0 +1,17 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "jest.config.ts", + "src/**/*.mock.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts", + "test/**/*.mock.ts", + "test/**/*.spec.ts" + ] +} diff --git a/packages/cluster/.eslintrc.json b/packages/cluster/.eslintrc.json new file mode 100644 index 0000000..69704e6 --- /dev/null +++ b/packages/cluster/.eslintrc.json @@ -0,0 +1,33 @@ +{ + "extends": ["../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.json"], + "parser": "jsonc-eslint-parser", + "rules": { + "@nx/dependency-checks": [ + "error", + { + "buildTargets": ["build"], + "checkMissingDependencies": true, + "checkObsoleteDependencies": true, + "checkVersionMismatches": true + } + ] + } + } + ] +} diff --git a/packages/cluster/README.md b/packages/cluster/README.md new file mode 100644 index 0000000..c78738e --- /dev/null +++ b/packages/cluster/README.md @@ -0,0 +1,11 @@ +# nestjs-tools-cluster + +This library was generated with [Nx](https://nx.dev). + +## Building + +Run `nx build nestjs-tools-cluster` to build the library. + +## Running unit tests + +Run `nx test nestjs-tools-cluster` to execute the unit tests via [Jest](https://jestjs.io). diff --git a/packages/cluster/fixtures/async.js b/packages/cluster/fixtures/async.js new file mode 100644 index 0000000..b757386 --- /dev/null +++ b/packages/cluster/fixtures/async.js @@ -0,0 +1,19 @@ +const { ClusterService } = require('../../../dist/packages/cluster'); + +const clusterService = new ClusterService({ + lifetime: 0, + workers: 1, +}); + +async function primary() { + await new Promise((r) => setTimeout(r, 500)); + console.log('primary'); +} +async function worker(_opts, disconnect) { + console.log('worker'); + disconnect(); +} +clusterService.clusterize(worker, primary).catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/packages/cluster/fixtures/cpus.js b/packages/cluster/fixtures/cpus.js new file mode 100644 index 0000000..3ea48e6 --- /dev/null +++ b/packages/cluster/fixtures/cpus.js @@ -0,0 +1,14 @@ +const { ClusterService } = require('../../../dist/packages/cluster'); + +const clusterService = new ClusterService({ + lifetime: 0, +}); + +const worker = () => { + console.log('worker'); + process.exit(); +}; +clusterService.clusterize(worker).catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/packages/cluster/fixtures/exit.js b/packages/cluster/fixtures/exit.js new file mode 100644 index 0000000..80b059f --- /dev/null +++ b/packages/cluster/fixtures/exit.js @@ -0,0 +1,14 @@ +const { ClusterService } = require('../../../dist/packages/cluster'); + +const clusterService = new ClusterService({ + workers: 3, + lifetime: 0, +}); +const worker = () => { + console.log('worker'); + process.exit(); +}; +clusterService.clusterize(worker).catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/packages/cluster/fixtures/graceful-sigusr2.js b/packages/cluster/fixtures/graceful-sigusr2.js new file mode 100644 index 0000000..0e7a9d4 --- /dev/null +++ b/packages/cluster/fixtures/graceful-sigusr2.js @@ -0,0 +1,24 @@ +const { ClusterService } = require('../../../dist/packages/cluster'); + +const clusterService = new ClusterService({ + workers: 2, + signals: ['SIGUSR2'], +}); + +const worker = (_opts, disconnect) => { + let exited = false; + console.log('worker'); + process.on('SIGUSR2', exit); + + async function exit() { + if (exited) return; + exited = true; + console.log(`exiting`); + disconnect(); + } +}; + +clusterService.clusterize(worker).catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/packages/cluster/fixtures/graceful.js b/packages/cluster/fixtures/graceful.js new file mode 100644 index 0000000..17f3ed6 --- /dev/null +++ b/packages/cluster/fixtures/graceful.js @@ -0,0 +1,26 @@ +const { ClusterService } = require('../../../dist/packages/cluster'); + +const clusterService = new ClusterService({ + workers: 2, +}); + +const worker = (_opts, disconnect) => { + let exited = false; + console.log('worker'); + process.on('SIGTERM', exit); + process.on('SIGINT', exit); + + async function exit() { + if (exited) return; + exited = true; + + await new Promise((r) => setTimeout(r, 100)); // simulate async cleanup + console.log('exiting'); + disconnect(); + } +}; + +clusterService.clusterize(worker).catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/packages/cluster/fixtures/infinite.js b/packages/cluster/fixtures/infinite.js new file mode 100644 index 0000000..c13cc12 --- /dev/null +++ b/packages/cluster/fixtures/infinite.js @@ -0,0 +1,11 @@ +const { ClusterService } = require('../../../dist/packages/cluster'); + +const clusterService = new ClusterService({ workers: 3 }); +const worker = () => { + console.log('worker'); + process.exit(); +}; +clusterService.clusterize(worker).catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/packages/cluster/fixtures/kill.js b/packages/cluster/fixtures/kill.js new file mode 100644 index 0000000..8cb0261 --- /dev/null +++ b/packages/cluster/fixtures/kill.js @@ -0,0 +1,23 @@ +const { ClusterService } = require('../../../dist/packages/cluster'); + +const clusterService = new ClusterService({ + workers: 2, + lifetime: 0, + grace: 250, +}); + +const worker = () => { + console.log('ah ha ha ha'); + + process.once('SIGTERM', function () { + console.log('stayin alive'); + }); + + // console.log('worker'); + // process.exit(); +}; + +clusterService.clusterize(worker).catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/packages/cluster/fixtures/lifetime.js b/packages/cluster/fixtures/lifetime.js new file mode 100644 index 0000000..82bdf80 --- /dev/null +++ b/packages/cluster/fixtures/lifetime.js @@ -0,0 +1,17 @@ +const { ClusterService } = require('../../../dist/packages/cluster'); + +const clusterService = new ClusterService({ + workers: 3, + lifetime: 500, + restartOnExit: true, +}); + +const worker = () => { + console.log('worker'); + process.exit(); +}; + +clusterService.clusterize(worker).catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/packages/cluster/fixtures/primary.js b/packages/cluster/fixtures/primary.js new file mode 100644 index 0000000..8840e32 --- /dev/null +++ b/packages/cluster/fixtures/primary.js @@ -0,0 +1,20 @@ +const { ClusterService } = require('../../../dist/packages/cluster'); + +const clusterService = new ClusterService({ + workers: 2, + lifetime: 0, +}); + +const worker = () => { + console.log('worker'); + process.exit(); +}; + +const primary = () => { + console.log('primary'); +}; + +clusterService.clusterize(worker, primary).catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/packages/cluster/jest.config.ts b/packages/cluster/jest.config.ts new file mode 100644 index 0000000..bedcfc4 --- /dev/null +++ b/packages/cluster/jest.config.ts @@ -0,0 +1,11 @@ +/* eslint-disable */ +export default { + displayName: 'nestjs-tools-cluster', + preset: '../../jest.preset.js', + testEnvironment: 'node', + transform: { + '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }], + }, + moduleFileExtensions: ['ts', 'js', 'html'], + coverageDirectory: '../../coverage/packages/cluster', +}; diff --git a/packages/cluster/package.json b/packages/cluster/package.json new file mode 100644 index 0000000..4bb6a7e --- /dev/null +++ b/packages/cluster/package.json @@ -0,0 +1,28 @@ +{ + "name": "@getlarge/nestjs-tools-cluster", + "version": "0.15.5", + "description": "Cluster and workers manager", + "keywords": [ + "cluster", + "worker", + "node", + "scale", + "nestjs" + ], + "license": "Apache-2.0", + "author": "Edouard Maleix ", + "homepage": "https://github.com/getlarge/nestjs-tools/tree/main/packages/cluster", + "publishConfig": { + "registry": "https://registry.npmjs.org/" + }, + "publicConfig": { + "access": "public" + }, + "dependencies": { + "tslib": "^2.3.0", + "@getlarge/typed-event-emitter": "0.1.1" + }, + "type": "commonjs", + "main": "./src/index.js", + "typings": "./src/index.d.ts" +} diff --git a/packages/cluster/project.json b/packages/cluster/project.json new file mode 100644 index 0000000..5dc578d --- /dev/null +++ b/packages/cluster/project.json @@ -0,0 +1,30 @@ +{ + "name": "nestjs-tools-cluster", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "packages/cluster/src", + "projectType": "library", + "tags": [], + "targets": { + "build": { + "executor": "@nx/js:tsc", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/packages/cluster", + "tsConfig": "packages/cluster/tsconfig.lib.json", + "packageJson": "packages/cluster/package.json", + "main": "packages/cluster/src/index.ts", + "assets": ["packages/cluster/*.md"], + "external": "none" + } + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "dependsOn": ["build"], + "options": { + "jestConfig": "packages/cluster/jest.config.ts", + "codeCoverage": true + } + } + } +} diff --git a/packages/cluster/src/index.ts b/packages/cluster/src/index.ts new file mode 100644 index 0000000..e0de65c --- /dev/null +++ b/packages/cluster/src/index.ts @@ -0,0 +1 @@ +export * from './lib/cluster.service'; diff --git a/packages/cluster/src/lib/cluster.service.ts b/packages/cluster/src/lib/cluster.service.ts new file mode 100644 index 0000000..cad4390 --- /dev/null +++ b/packages/cluster/src/lib/cluster.service.ts @@ -0,0 +1,181 @@ +// inspired by https://github.com/hunterloftis/throng/blob/master/lib/throng.js +import { EventHandlers, TypedEventEmitter } from '@getlarge/typed-event-emitter'; +import cluster, { Worker } from 'node:cluster'; +import { cpus } from 'node:os'; +import { Serializable } from 'node:worker_threads'; + +type Logger = Pick; + +export type ClusterServiceConfig = { + workers?: number; + showLogs?: boolean; + delay?: number; + restartOnExit?: boolean; + lifetime?: number; + grace?: number; + signals?: NodeJS.Signals[]; + logger?: Logger; +}; + +export interface ClusterServiceEmissions extends EventHandlers { + online: (worker: Worker) => void; + disconnect: (worker: Worker) => void; + revive: (worker: Worker) => void; + message: (worker: Worker, message: unknown) => void; + ready: () => void; + error: (error: Error) => void; +} + +export type WorkerFn = ( + opts: { workerId?: number }, + disconnect: (workerId?: number) => void, + send: (message: Serializable, workerId?: number) => void, +) => void | Promise; + +export type PrimaryFn = () => void | Promise; + +// eslint-disable-next-line @typescript-eslint/no-empty-function +const noOp: PrimaryFn = () => {}; + +export class ClusterService extends TypedEventEmitter { + readonly logger: Logger; + private showLogs: boolean; + private restartOnExit: boolean; + private delay: number; + private lifetime: number; + private grace: number; + private reviveUntil: number; + private signals: NodeJS.Signals[]; + private workersCount: number; + private running = false; + + constructor(private config: ClusterServiceConfig = {}) { + super({ captureRejections: true }); + this.logger = this.config.logger || console; + this.restartOnExit = this.config.restartOnExit || false; + this.showLogs = this.config.showLogs || false; + this.workersCount = typeof this.config.workers === 'number' ? this.config.workers : cpus().length; + this.delay = this.config.delay || 0; + this.lifetime = typeof this.config.lifetime === 'number' ? this.config.lifetime : Infinity; + this.reviveUntil = Date.now() + this.lifetime; + this.grace = typeof this.config.grace === 'number' ? this.config.grace : 5000; + this.signals = this.config.signals || ['SIGTERM', 'SIGINT']; + } + + /* + * @deprecated + */ + get isMaster() { + return cluster.isPrimary; + } + + get isPrimary() { + return cluster.isPrimary; + } + + get isWorker() { + return cluster.isWorker; + } + + get workerId() { + return cluster.worker?.id; + } + + get workers() { + return cluster.workers; + } + + log(message: unknown): void { + this.showLogs && this.logger.log(message); + } + + async fork(): Promise { + for (let i = 0; i < this.workersCount; i++) { + await new Promise((resolve) => setTimeout(resolve, this.delay)); + cluster.fork(); + } + } + + async clusterize(workerFn: WorkerFn, primaryFn: PrimaryFn = noOp): Promise { + if (typeof workerFn !== 'function') { + throw new TypeError('Start function required'); + } + + if (cluster.isWorker) { + await workerFn.bind(this)({ workerId: this.workerId }, this.disconnect, this.send); + return this.workerId as number; + } + + this.reviveUntil = Date.now() + this.lifetime; + this.running = true; + this.listen(); + await primaryFn(); + await this.fork(); + this.emit('ready'); + return 0; + } + + listen(): void { + cluster.on('online', (worker) => { + this.log(`Worker ${worker.process.pid} is online`); + this.emit('online', worker); + }); + cluster.on('message', (worker, message) => { + this.emit('message', worker, message); + }); + cluster.on('disconnect', (worker) => this.revive(worker)); + this.signals.forEach((signal) => process.on(signal, this.shutdown(signal))); + } + + shutdown(signal: NodeJS.Signals): (killProcess?: boolean) => void { + return (killProcess = true) => { + this.running = false; + setTimeout(() => this.forceKill(signal, killProcess), this.grace).unref(); + for (const worker of Object.values(cluster.workers ?? [])) { + worker?.process.kill(signal); + worker?.removeAllListeners(); + } + }; + } + + revive(worker: Worker): void { + this.log(`Worker ${worker.process.pid} is disconnected`); + this.emit('disconnect', worker); + if (!this.running) return; + if (!this.restartOnExit) return; + if (Date.now() >= this.reviveUntil) return; + this.emit('revive', worker); + cluster.fork(); + } + + forceKill(signal: NodeJS.Signals, killProcess = true): void { + for (const worker of Object.values(cluster.workers ?? [])) { + worker?.kill(signal); + } + this.removeAllListeners(); + this.log('Kill process'); + killProcess && process.exit(0); + } + + kill(workerId: number): void { + cluster.workers?.[workerId]?.process?.kill(); + } + + send(msg: Serializable, workerId?: number): void { + if (typeof workerId === 'number' && this.isPrimary) { + cluster.workers?.[workerId]?.send(msg); + } else { + cluster.worker?.send(msg); + } + } + + disconnect(workerId?: number): void { + setTimeout(() => { + if (typeof workerId === 'number' && this.isPrimary) { + cluster.workers?.[workerId]?.disconnect(); + } else { + cluster.worker?.disconnect(); + } + }, 50); + } +} diff --git a/packages/cluster/test/cluster.service.spec.ts b/packages/cluster/test/cluster.service.spec.ts new file mode 100644 index 0000000..398e8bc --- /dev/null +++ b/packages/cluster/test/cluster.service.spec.ts @@ -0,0 +1,265 @@ +/* eslint-disable max-lines-per-function */ +import { ChildProcessWithoutNullStreams, spawn } from 'node:child_process'; +import { cpus } from 'node:os'; +import { join } from 'node:path'; +import { setTimeout } from 'node:timers/promises'; + +import { ClusterService, WorkerFn } from '../src'; + +const cpuCount = cpus().length; + +enum Fixtures { + throws = 'throws', + exit = 'exit', + lifetime = 'lifetime', + infinite = 'infinite', + cpus = 'cpus', + primary = 'primary', + kill = 'kill', + graceful = 'graceful', + 'graceful-sigusr2' = 'graceful-sigusr2', + async = 'async', +} + +function run(file: string): { + child: ChildProcessWithoutNullStreams; + done: Promise<{ out: string; time: number }>; +} { + const child = spawn('node', [file], { detached: true }); + const startTime = Date.now(); + let out = ''; + + child.stdout.on('data', (data) => (out += data.toString())); + child.stderr.on('data', (data) => (out += data.toString())); + + const done = new Promise<{ out: string; time: number }>((resolve) => { + child.on('exit', () => { + resolve({ out, time: Date.now() - startTime }); + }); + }); + + return { child, done }; +} + +function getFixture(name: Fixtures) { + return join(__dirname, '../fixtures', name); +} + +describe('ClusterService', function () { + it('should throw an error when no worker function is provided', async () => { + const expectedError = 'Start function required'; + // + const clusterService = new ClusterService(); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + await expect(clusterService.clusterize('not_a_function' as any)).rejects.toThrow(new Error(expectedError)); + }); + + it('should emit online event when a new worker is online', async () => { + const workersOnline: Record = { 1: false, 2: false }; + const clusterService = new ClusterService({ + workers: 2, + lifetime: 0, + showLogs: true, + }); + const abortController = new AbortController(); + let _workerCount = 0; + const workerFn: WorkerFn = (opts, disconnect) => { + disconnect?.(); + }; + // + await clusterService.clusterize(workerFn); + // + setTimeout(1000, { signal: abortController.signal }).then(() => abortController.abort()); + for await (const [worker] of clusterService.wait('online', { + signal: abortController.signal, + })) { + workersOnline[worker.id] = true; + _workerCount += 1; + if (_workerCount === 2) { + break; + } + } + for (const workerId of Object.keys(workersOnline)) { + clusterService.kill(Number(workerId)); + } + clusterService.shutdown('SIGTERM')(false); + abortController.abort(); + expect(Object.values(workersOnline).every((s) => s === true)).toBe(true); + }); + + it('should emit disconnect event when a worker is disconnected', async () => { + const clusterService = new ClusterService({ + workers: 1, + lifetime: 0, + }); + const workerFn: WorkerFn = (opts, disconnect) => { + disconnect?.(); + }; + const abortController = new AbortController(); + // + const p1 = clusterService.waitOnce('online').then(([worker]) => worker.id); + const p2 = clusterService + .waitOnce('disconnect', { + signal: abortController.signal, + }) + .then(() => true); + await clusterService.clusterize(workerFn); + // + const workerId = await p1; + clusterService.kill(workerId); + clusterService.shutdown('SIGTERM')(false); + setTimeout(500, { signal: abortController.signal }).then(() => abortController.abort()); + const workerOffline = await p2; + abortController.abort(); + expect(workerOffline).toBe(true); + }); + + it('should emit message event when a worker sends a message', async () => { + const baseMessage = 'hello from worker'; + const clusterService = new ClusterService({ + workers: 1, + lifetime: 0, + }); + const workerFn: WorkerFn = (opts, disconnect, send) => { + // this send method is not triggered by the test + send(`${baseMessage} ${opts.workerId} ${process.pid}`); + disconnect?.(); + }; + const abortController = new AbortController(); + // + const p2 = clusterService + .waitOnce('online', { + signal: abortController.signal, + }) + .then(([worker]) => { + const p = clusterService.waitOnce('message', { + signal: abortController.signal, + }); + worker.emit('message', `${baseMessage} ${worker.id} ${process.pid}`); + return p; + }) + .then(([worker, msg]) => ({ worker, msg })); + await clusterService.clusterize(workerFn); + // + const { msg } = await p2; + clusterService.shutdown('SIGTERM')(false); + setTimeout(500, { signal: abortController.signal }).then(() => abortController.abort()); + abortController.abort(); + expect(msg).toEqual(expect.stringContaining(baseMessage)); + }); + + it('should start one worker per CPU when no worker count specified', async () => { + const { child, done } = run(getFixture(Fixtures.cpus)); + const { out } = await done; + const workers = out.match(/worker/g)?.length; + child.kill(); + expect(workers).toBe(cpuCount); + }, 8000); + + it('should complete primary before starting workers when using sync primary and worker functions', async () => { + const { child, done } = run(getFixture(Fixtures.async)); + const { out } = await done; + child.kill(); + expect(out).toBe('primary\nworker\n'); + }, 9000); + + describe('with a worker function and 3 workers', () => { + if (process.env['CI']) return; // those tests are kind of flaky in Github CI runner... + + it('should start 3 workers that immediately exit, with lifetime of 0', async () => { + const { done } = run(getFixture(Fixtures.exit)); + const { out, time } = await done; + const workers = out.match(/worker/g)?.length; + expect(workers).toBe(3); + expect(time).toBeLessThan(200); + }, 8000); + + it('should start 3 workers repeatedly and keep workers running for at least 500ms, with lifetime of 500ms', async () => { + const { done } = run(getFixture(Fixtures.lifetime)); + const { out, time } = await done; + const workers = out.match(/worker/g)?.length; + expect(workers).toBeGreaterThanOrEqual(3); + expect(time).toBeGreaterThan(500); + }, 8000); + + it('should start 3 workers repeatedly and keep workers running until killed externally, with no lifetime specified', async () => { + const delay = 2000; + const { child, done } = run(getFixture(Fixtures.infinite)); + setTimeout(delay).then(() => child.kill()); + const { out } = await done; + const workers = out.match(/worker/g)?.length; + expect(workers).toBeGreaterThanOrEqual(3); + // expect(time).toBeGreaterThanOrEqual(delay - 1000); + // expect(time).toBeLessThan(delay); + }, 8000); + }); + + describe('with a primary function and two workers', () => { + let output: string; + + beforeAll(async () => { + const { done } = run(getFixture(Fixtures.primary)); + const { out } = await done; + output = out; + }, 8000); + + it('should start one primary', () => { + const primary = output.match(/primary/g)?.length; + expect(primary).toBe(1); + }); + + it('should start two workers', () => { + const workers = output.match(/worker/g)?.length; + expect(workers).toBe(2); + }); + }); + + describe('signal handling', () => { + if (process.platform === 'win32') return; // windows does not support signal-based process shutdown + if (process.env['CI']) return; // those tests are kind of flaky in Github CI runner... + const delay = 1000; + + it('should start 2 workers and allow them to shut down, when SIGTERM with 2 workers that exit gracefully', async () => { + const { child, done } = run(getFixture(Fixtures.graceful)); + setTimeout(delay).then(() => child.kill()); + const { out } = await done; + const workers = out.match(/worker/g)?.length; + expect(workers).toBe(2); + const exits = out.match(/exiting/g)?.length; + expect(exits).toBe(2); + }); + + it('should start 2 workers and notify them that they should exit, when SIGTERM with 2 workers that fail to exit', async () => { + const { child, done } = run(getFixture(Fixtures.kill)); + setTimeout(delay).then(() => child.kill()); + const { out } = await done; + const workers = out.match(/ah ha ha ha/g)?.length; + expect(workers).toBe(2); + const exits = out.match(/stayin alive/g)?.length; + expect(exits).toBe(2); + // expect(time).toBeGreaterThanOrEqual(1250); + // expect(time).toBeLessThan(1350); + }); + + it('should start 2 workers and allow them to shut down when SIGINT on the process group (Ctrl+C) with 2 workers that exit gracefully', async () => { + const { child, done } = run(getFixture(Fixtures.graceful)); + setTimeout(delay).then(() => (child.pid ? process.kill(-child.pid, 'SIGINT') : void 0)); + + const { out } = await done; + const workers = out.match(/worker/g)?.length; + expect(workers).toBe(2); + const exits = out.match(/exiting/g)?.length; + expect(exits).toBe(2); + }); + + it('should start 2 workers and allow them to shut down when using custom shutdown signal with 2 workers that exit gracefully', async () => { + const { child, done } = run(getFixture(Fixtures['graceful-sigusr2'])); + setTimeout(delay).then(() => child.kill('SIGUSR2')); + const { out } = await done; + const workers = out.match(/worker/g)?.length; + expect(workers).toBe(2); + const exits = out.match(/exiting/g)?.length; + expect(exits).toBe(2); + }); + }); +}); diff --git a/packages/cluster/tsconfig.json b/packages/cluster/tsconfig.json new file mode 100644 index 0000000..ab06590 --- /dev/null +++ b/packages/cluster/tsconfig.json @@ -0,0 +1,23 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "module": "commonjs", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "esModuleInterop": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/packages/cluster/tsconfig.lib.json b/packages/cluster/tsconfig.lib.json new file mode 100644 index 0000000..d85850b --- /dev/null +++ b/packages/cluster/tsconfig.lib.json @@ -0,0 +1,16 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "declaration": true, + "types": ["node"], + "target": "es2021", + "strictNullChecks": true, + "noImplicitAny": true, + "strictBindCallApply": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src/**/*.ts"], + "exclude": ["jest.config.ts", "src/**/*.mock.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] +} diff --git a/packages/cluster/tsconfig.spec.json b/packages/cluster/tsconfig.spec.json new file mode 100644 index 0000000..07412f0 --- /dev/null +++ b/packages/cluster/tsconfig.spec.json @@ -0,0 +1,17 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "jest.config.ts", + "src/**/*.mock.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts", + "test/**/*.mock.ts", + "test/**/*.spec.ts" + ] +} diff --git a/packages/file-storage/.env.test.sample b/packages/file-storage/.env.test.sample new file mode 100644 index 0000000..1804073 --- /dev/null +++ b/packages/file-storage/.env.test.sample @@ -0,0 +1,6 @@ +S3_ACCESS_KEY_ID= +S3_BUCKET= +# either use S3_ENDPOINT or S3_REGION +S3_REGION=eu-central-1 +S3_ENDPOINT=https://s3.eu-central-1.amazonaws.com/ +S3_SECRET_ACCESS_KEY= diff --git a/packages/file-storage/.eslintrc.json b/packages/file-storage/.eslintrc.json new file mode 100644 index 0000000..69704e6 --- /dev/null +++ b/packages/file-storage/.eslintrc.json @@ -0,0 +1,33 @@ +{ + "extends": ["../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.json"], + "parser": "jsonc-eslint-parser", + "rules": { + "@nx/dependency-checks": [ + "error", + { + "buildTargets": ["build"], + "checkMissingDependencies": true, + "checkObsoleteDependencies": true, + "checkVersionMismatches": true + } + ] + } + } + ] +} diff --git a/packages/file-storage/CHANGELOG.md b/packages/file-storage/CHANGELOG.md new file mode 100644 index 0000000..c615855 --- /dev/null +++ b/packages/file-storage/CHANGELOG.md @@ -0,0 +1,449 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +# [0.8.0](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-file-storage@0.7.0...@s1seven/nestjs-tools-file-storage@0.8.0) (2023-10-11) + +### Features + +- **file-storage:** create FileStorageWritable type with `done` event ([6eed261](https://github.com/s1seven/nestjs-tools/commit/6eed261c06f147f5bddd2b9e643da2c52fcd32af)) +- **file-storage:** emit 'done' event once file is fully written ([f8b1a02](https://github.com/s1seven/nestjs-tools/commit/f8b1a02eef9924f51da3105315cb476d643865d7)) + +# [0.7.0](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-file-storage@0.6.3...@s1seven/nestjs-tools-file-storage@0.7.0) (2023-09-04) + +### Bug Fixes + +- **file-storage:** correctly spread credentials propetry ([f26ed81](https://github.com/s1seven/nestjs-tools/commit/f26ed8130cf14eb25fc5dcc57b92b6e7391c0857)) +- **file-storage:** update types and imports ([fe68063](https://github.com/s1seven/nestjs-tools/commit/fe680630c9392f85d6920f243ceb6eec65ba5596)) + +### Features + +- **file-storage:** allow custom S3 logger and make config readonly ([2a09f02](https://github.com/s1seven/nestjs-tools/commit/2a09f0238ea26bf057e6df1c5b301cf22a6ea07f)) + +## [0.6.3](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-file-storage@0.6.2...@s1seven/nestjs-tools-file-storage@0.6.3) (2023-04-05) + +**Note:** Version bump only for package @s1seven/nestjs-tools-file-storage + +## [0.6.2](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-file-storage@0.6.1...@s1seven/nestjs-tools-file-storage@0.6.2) (2023-04-04) + +### Bug Fixes + +- return folders and filenames from readDir S3 ([d6437fa](https://github.com/s1seven/nestjs-tools/commit/d6437fa5155177baf7ed13dfafaa527e82731256)) + +## [0.6.1](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-file-storage@0.6.0...@s1seven/nestjs-tools-file-storage@0.6.1) (2022-11-30) + +### Bug Fixes + +- **file-storage:** update invalid type check ([397f877](https://github.com/s1seven/nestjs-tools/commit/397f8776766aec97c96cfe70067935c03b6496bf)) + +### Reverts + +- **file-storage:** come back to computed property ([76f6680](https://github.com/s1seven/nestjs-tools/commit/76f6680bb1e1157aea5b8ac168c05a846d498751)) + +# [0.6.0](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-file-storage@0.5.0...@s1seven/nestjs-tools-file-storage@0.6.0) (2022-10-31) + +### Bug Fixes + +- **file-storage:** update stream methods return type ([4de6fc8](https://github.com/s1seven/nestjs-tools/commit/4de6fc8c45a6189dc6348fa540928c0181f42c84)) +- **file-storage:** use S3 managed upload to make writeStream work ([8f9a314](https://github.com/s1seven/nestjs-tools/commit/8f9a31425e367f4a1d8a3921a820ba9291b5090e)) + +### Features + +- **file-storage:** create and apply internal MethodType ([b77fdc0](https://github.com/s1seven/nestjs-tools/commit/b77fdc0071521415ce7afc7270cf281d365fc1bb)) + +# [0.5.0](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-file-storage@0.4.8...@s1seven/nestjs-tools-file-storage@0.5.0) (2022-10-27) + +### Bug Fixes + +- **file-storage:** remove `toLowerCase` ([4245d45](https://github.com/s1seven/nestjs-tools/commit/4245d450a9159e75337db9131c9c6c9e8ba01d67)) + +### Features + +- add deleteDir and readDir methods to FileStorageLocal ([f32db73](https://github.com/s1seven/nestjs-tools/commit/f32db730d058e0f9597cdd85b2490961fb932e1d)) +- add deleteDir and readDir methods to FileStorageS3 ([1f9d517](https://github.com/s1seven/nestjs-tools/commit/1f9d5178960996adf68562ef75c9f19029a6f26e)) +- **file-storage:** create `FileStorageModule` ([07237e1](https://github.com/s1seven/nestjs-tools/commit/07237e1321468ba167fd5b5957e5c24a590d0f5f)) +- **file-storage:** create `FileStorageService` ([e332a0e](https://github.com/s1seven/nestjs-tools/commit/e332a0ecfa4d91253c01c9d2ff0c0dd7b4fbd885)) + +## [0.4.8](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-file-storage@0.4.7...@s1seven/nestjs-tools-file-storage@0.4.8) (2022-08-09) + +**Note:** Version bump only for package @s1seven/nestjs-tools-file-storage + +## [0.4.7](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-file-storage@0.4.6...@s1seven/nestjs-tools-file-storage@0.4.7) (2022-06-02) + +**Note:** Version bump only for package @s1seven/nestjs-tools-file-storage + +## 0.4.6 (2022-03-17) + +**Note:** Version bump only for package @s1seven/nestjs-tools-file-storage + +## [0.4.5](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.4.4...@s1seven/microservices-file-storage@0.4.5) (2022-02-10) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.4.4](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.4.3...@s1seven/microservices-file-storage@0.4.4) (2021-11-22) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.4.3](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.4.2...@s1seven/microservices-file-storage@0.4.3) (2021-10-29) + +### Bug Fixes + +- **file-storage:** update FS type ([ee7f693](https://github.com/s1seven/microservices-common/commit/ee7f693036995340ce39bd2fb45c8ab5caa06348)) + +## [0.4.2](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.4.1...@s1seven/microservices-file-storage@0.4.2) (2021-10-08) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.4.1](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.4.0...@s1seven/microservices-file-storage@0.4.1) (2021-10-07) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +# [0.4.0](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.32...@s1seven/microservices-file-storage@0.4.0) (2021-09-28) + +### Features + +- add extra common class in FileStorage ([1deb63f](https://github.com/s1seven/microservices-common/commit/1deb63f2289b194cee260e928be3ebb7a73e198b)) + +## [0.3.32](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.31...@s1seven/microservices-file-storage@0.3.32) (2021-09-24) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.3.31](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.30...@s1seven/microservices-file-storage@0.3.31) (2021-09-20) + +### Bug Fixes + +- update setup types ([2dd0e10](https://github.com/s1seven/microservices-common/commit/2dd0e10b8209444b4cb3fd5a30e4c7b63246f5b3)) + +## [0.3.30](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.29...@s1seven/microservices-file-storage@0.3.30) (2021-09-02) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.3.29](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.28...@s1seven/microservices-file-storage@0.3.29) (2021-09-02) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.3.28](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.27...@s1seven/microservices-file-storage@0.3.28) (2021-09-01) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.3.27](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.26...@s1seven/microservices-file-storage@0.3.27) (2021-08-27) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.3.26](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.25...@s1seven/microservices-file-storage@0.3.26) (2021-08-27) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.3.25](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.24...@s1seven/microservices-file-storage@0.3.25) (2021-08-23) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.3.24](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.23...@s1seven/microservices-file-storage@0.3.24) (2021-08-23) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.3.23](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.22...@s1seven/microservices-file-storage@0.3.23) (2021-08-06) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.3.22](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.21...@s1seven/microservices-file-storage@0.3.22) (2021-07-28) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.3.21](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.20...@s1seven/microservices-file-storage@0.3.21) (2021-07-26) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.3.20](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.19...@s1seven/microservices-file-storage@0.3.20) (2021-07-26) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.3.19](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.18...@s1seven/microservices-file-storage@0.3.19) (2021-07-20) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.3.18](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.17...@s1seven/microservices-file-storage@0.3.18) (2021-07-15) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.3.17](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.16...@s1seven/microservices-file-storage@0.3.17) (2021-07-12) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.3.16](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.15...@s1seven/microservices-file-storage@0.3.16) (2021-07-09) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.3.15](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.14...@s1seven/microservices-file-storage@0.3.15) (2021-07-08) + +### Bug Fixes + +- add config to lint command ([c9e099e](https://github.com/s1seven/microservices-common/commit/c9e099e5f85e916e6700f8caa2a3385c7e6193da)) +- lint ([9a2e6ac](https://github.com/s1seven/microservices-common/commit/9a2e6ac0b6ca1404d2c3856394167e8b56d2e8c0)) + +## [0.3.14](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.13...@s1seven/microservices-file-storage@0.3.14) (2021-07-02) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.3.13](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.12...@s1seven/microservices-file-storage@0.3.13) (2021-06-29) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.3.12](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.11...@s1seven/microservices-file-storage@0.3.12) (2021-06-24) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.3.11](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.10...@s1seven/microservices-file-storage@0.3.11) (2021-06-24) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.3.10](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.9...@s1seven/microservices-file-storage@0.3.10) (2021-06-23) + +### Bug Fixes + +- update lock files ([ffdff97](https://github.com/s1seven/microservices-common/commit/ffdff976fcca3197189a9fb8bc2401783d165421)) + +## [0.3.9](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.8...@s1seven/microservices-file-storage@0.3.9) (2021-06-22) + +### Bug Fixes + +- update lock files ([809eca0](https://github.com/s1seven/microservices-common/commit/809eca0bdf2ea84b8d1fa5256c923b8859cf43dd)) + +## [0.3.8](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.7...@s1seven/microservices-file-storage@0.3.8) (2021-06-22) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.3.7](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.6...@s1seven/microservices-file-storage@0.3.7) (2021-06-18) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.3.6](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.5...@s1seven/microservices-file-storage@0.3.6) (2021-06-16) + +### Bug Fixes + +- update lock files ([a664b61](https://github.com/s1seven/microservices-common/commit/a664b6104585c383ce980c67dd3fbd5fe466f57b)) + +## [0.3.5](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.4...@s1seven/microservices-file-storage@0.3.5) (2021-06-15) + +### Bug Fixes + +- update lock files ([f85a710](https://github.com/s1seven/microservices-common/commit/f85a710a47a181de0195f61e30c926503706b0e8)) + +## [0.3.4](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.3...@s1seven/microservices-file-storage@0.3.4) (2021-06-14) + +### Bug Fixes + +- update lock files ([21e3749](https://github.com/s1seven/microservices-common/commit/21e37491ed509ff00bc4a82575600c13e83334fc)) + +## [0.3.3](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.2...@s1seven/microservices-file-storage@0.3.3) (2021-06-08) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.3.2](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.1...@s1seven/microservices-file-storage@0.3.2) (2021-06-01) + +### Bug Fixes + +- update lock files ([540bff7](https://github.com/s1seven/microservices-common/commit/540bff76269fd062d0e101e4efbe02b90068e251)) + +## [0.3.1](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.3.0...@s1seven/microservices-file-storage@0.3.1) (2021-05-28) + +### Bug Fixes + +- update lock files ([c72828f](https://github.com/s1seven/microservices-common/commit/c72828f5c6a5938db641b38dbb5a9e04f49bed6a)) + +# [0.3.0](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.41...@s1seven/microservices-file-storage@0.3.0) (2021-05-27) + +### Features + +- change return type of transformFilePath ([5ed73f0](https://github.com/s1seven/microservices-common/commit/5ed73f057bb2938f8a3a0c2240c6c65ab5017ed6)) + +## [0.2.41](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.40...@s1seven/microservices-file-storage@0.2.41) (2021-05-25) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.40](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.39...@s1seven/microservices-file-storage@0.2.40) (2021-05-20) + +### Bug Fixes + +- cleanup code ([aea0191](https://github.com/s1seven/microservices-common/commit/aea0191371577031ef9816809aafa646f497ecf6)) +- remove duplicate strings ([460f68e](https://github.com/s1seven/microservices-common/commit/460f68e1b6a7b18f9d08d0eda1011bbc44b6ebcb)) +- update package lock ([e109680](https://github.com/s1seven/microservices-common/commit/e10968011e307b42020580418fa435f5c8e37632)) + +## [0.2.39](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.38...@s1seven/microservices-file-storage@0.2.39) (2021-05-06) + +### Bug Fixes + +- update package lock ([a463855](https://github.com/s1seven/microservices-common/commit/a4638552e2810e9b0e24bd684b67c90fa61a0519)) + +## [0.2.38](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.37...@s1seven/microservices-file-storage@0.2.38) (2021-05-03) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.37](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.36...@s1seven/microservices-file-storage@0.2.37) (2021-04-22) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.36](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.35...@s1seven/microservices-file-storage@0.2.36) (2021-04-21) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.35](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.34...@s1seven/microservices-file-storage@0.2.35) (2021-04-21) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.34](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.33...@s1seven/microservices-file-storage@0.2.34) (2021-04-20) + +### Bug Fixes + +- update package lock ([68e574b](https://github.com/s1seven/microservices-common/commit/68e574bc28349a41cbd9a94b9591601521918cb5)) + +## [0.2.33](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.32...@s1seven/microservices-file-storage@0.2.33) (2021-04-16) + +### Bug Fixes + +- update pkg lock ([cb8db23](https://github.com/s1seven/microservices-common/commit/cb8db233b03e9f47d9213854774da1748824087d)) + +## [0.2.32](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.31...@s1seven/microservices-file-storage@0.2.32) (2021-04-16) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.31](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.30...@s1seven/microservices-file-storage@0.2.31) (2021-04-16) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.30](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.29...@s1seven/microservices-file-storage@0.2.30) (2021-04-14) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.29](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.28...@s1seven/microservices-file-storage@0.2.29) (2021-04-13) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.28](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.27...@s1seven/microservices-file-storage@0.2.28) (2021-04-12) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.27](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.26...@s1seven/microservices-file-storage@0.2.27) (2021-04-09) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.26](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.25...@s1seven/microservices-file-storage@0.2.26) (2021-04-08) + +### Bug Fixes + +- update package lock ([bc06109](https://github.com/s1seven/microservices-common/commit/bc06109abaf4080ffe406998bc5b587554390460)) + +## [0.2.25](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.24...@s1seven/microservices-file-storage@0.2.25) (2021-04-07) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.24](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.23...@s1seven/microservices-file-storage@0.2.24) (2021-04-02) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.23](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.22...@s1seven/microservices-file-storage@0.2.23) (2021-04-02) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.22](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.21...@s1seven/microservices-file-storage@0.2.22) (2021-03-30) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.21](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.20...@s1seven/microservices-file-storage@0.2.21) (2021-03-29) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.20](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.19...@s1seven/microservices-file-storage@0.2.20) (2021-03-29) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.19](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.18...@s1seven/microservices-file-storage@0.2.19) (2021-03-24) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.18](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.17...@s1seven/microservices-file-storage@0.2.18) (2021-03-23) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.17](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.16...@s1seven/microservices-file-storage@0.2.17) (2021-03-23) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.16](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.15...@s1seven/microservices-file-storage@0.2.16) (2021-03-23) + +### Bug Fixes + +- package conf ([b459fcf](https://github.com/s1seven/microservices-common/commit/b459fcfb84e821751a76be51a3e7c3bd14b6b3e7)) + +## [0.2.15](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.14...@s1seven/microservices-file-storage@0.2.15) (2021-03-23) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.14](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.13...@s1seven/microservices-file-storage@0.2.14) (2021-03-22) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.13](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.12...@s1seven/microservices-file-storage@0.2.13) (2021-03-15) + +### Bug Fixes + +- update dependencies ([c4c5c20](https://github.com/s1seven/microservices-common/commit/c4c5c205f5a6c04ab24151a849ebb22652967ebd)) + +## [0.2.12](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.11...@s1seven/microservices-file-storage@0.2.12) (2021-03-11) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.11](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.10...@s1seven/microservices-file-storage@0.2.11) (2021-03-03) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.10](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.9...@s1seven/microservices-file-storage@0.2.10) (2021-03-03) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.9](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.8...@s1seven/microservices-file-storage@0.2.9) (2021-02-09) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.8](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.7...@s1seven/microservices-file-storage@0.2.8) (2021-02-08) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.7](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.6...@s1seven/microservices-file-storage@0.2.7) (2021-02-05) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.6](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.5...@s1seven/microservices-file-storage@0.2.6) (2021-02-05) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.5](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.4...@s1seven/microservices-file-storage@0.2.5) (2021-02-04) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.4](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.3...@s1seven/microservices-file-storage@0.2.4) (2021-02-04) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.3](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.2...@s1seven/microservices-file-storage@0.2.3) (2021-02-02) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.2](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.1...@s1seven/microservices-file-storage@0.2.2) (2021-02-01) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +## [0.2.1](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-file-storage@0.2.0...@s1seven/microservices-file-storage@0.2.1) (2021-02-01) + +**Note:** Version bump only for package @s1seven/microservices-file-storage + +# 0.2.0 (2021-01-27) + +### Bug Fixes + +- improve types and add fileExists methodร ([fd655f5](https://github.com/s1seven/microservices-common/commit/fd655f5bb95a74fb60963db7232471d1ff2593ca)) + +### Features + +- migrate project to lerna ([fef948c](https://github.com/s1seven/microservices-common/commit/fef948c31e20e2f5b929a41a0ad09ae17bb3729f)) diff --git a/packages/file-storage/README.md b/packages/file-storage/README.md new file mode 100644 index 0000000..8634207 --- /dev/null +++ b/packages/file-storage/README.md @@ -0,0 +1,164 @@ +# File-storage + +[![npm][npm-image]][npm-url] + +[npm-image]: https://img.shields.io/npm/v/@getlarge/nestjs-tools-file-storage.svg?style=flat +[npm-url]: https://npmjs.org/package/@getlarge/nestjs-tools-file-storage + +File storage classes for : + +- Node FileSystem +- Amazon S3 + +NOTE: release `@getlarge/nestjs-tools-file-storage@0.6.2` has some breaking changes as we now use AWS SDK v3: + +- `accessKeyId` and `secretAccessKey` should be passed to `FileStorageS3Setup` as properties of a `credentials` object. +- The `s3BucketEndpoint` property has been removed. +- In AWS SDK v3, the `endpoint` property has been replaced by `region`. For compatibility, we currently extract the region from an `endpoint` url if it is present and the `region` property is not, but you should update to `region` as this may change in future updates. + +## Installation + +```bash +$ npm install --save @getlarge/nestjs-tools-file-storage +``` + +## Example + +```ts +import { AppConfigService } from '@app/env'; +import { Inject, Injectable, Logger } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { SymmetricCipher } from '@bigchaindb/wallet-plugins'; +import { + FileStorage, + FileStorageConfig, + FileStorageLocal, + FileStorageLocalSetup, + FileStorageS3, + FileStorageS3Config, + FileStorageS3Setup, +} from '@getlarge/nestjs-tools-file-storage'; +import { S3 } from '@aws-sdk/client-s3'; +import { Upload } from '@aws-sdk/lib-storage'; +import { Request } from 'express'; +import { isBase64 } from 'class-validator'; +import chalk from 'chalk'; +import { existsSync, mkdirSync, writeFileSync } from 'fs'; +import { join, resolve } from 'path'; +import { decodeBase64 } from 'tweetnacl-util'; + +function fileStorageConfigFactory(setup: FileStorageLocalSetup & { secretKeyPath: string }): FileStorageConfig { + const { maxPayloadSize, storagePath, secretKeyPath } = setup; + const filePath = (options: { req?: Request; fileName: string }): string => { + const { fileName } = options; + if (!existsSync(storagePath)) { + mkdirSync(storagePath, { recursive: true }); + } + const path = resolve(join(storagePath, fileName)); + if (!existsSync(path) && fileName === secretKeyPath) { + writeFileSync(path, ''); + } + return path; + }; + const limits = { fileSize: maxPayloadSize * 1024 * 1024 }; + return { filePath, limits }; +} + +function s3StorageConfigFactory( + setup: FileStoragS3Setup & { secretKeyPath: string }, +): FileStorageConfig & FileStorageS3Config { + const { bucket, maxPayloadSize, credentials, region } = setup; + const s3 = new S3({ + credentials, + region, + }); + const filePath = async (options: { request?: Request; fileName: string }): Promise => { + const { fileName } = options; + const fileExists = await s3 + .headObject({ Key: fileName, Bucket: bucket }) + .promise() + .then(() => true) + .catch(() => false); + if (!fileExists && fileName === secretKeyPath) { + await new Upload({ + client: s3, + params: { Bucket: bucket, Key: fileName, Body: '' }, + }).done(); + } + return `${fileName}`; + }; + + const limits = { fileSize: maxPayloadSize * 1024 * 1024 }; + return { + s3, + bucket, + filePath, + limits, + }; +} + +@Injectable() +export class StorageService { + readonly logger = new Logger(StorageService.name); + readonly fileStorage: FileStorage; + + constructor(@Inject(ConfigService) private readonly configService: AppConfigService) { + const environment = this.configService.get('NODE_ENV'); + if (!environment || environment === 'development' || environment === 'test') { + const setup: FileStorageLocalSetup = { + secretKeyPath: configService.get('SECRET_KEY_PATH'), + storagePath: configService.get('STORAGE_PATH'), + maxPayloadSize: configService.get('MAX_PAYLOAD_SIZE'), + }; + this.fileStorage = new FileStorageLocal(setup, fileStorageConfigFactory); + } else { + const setup: FileStorageS3Setup = { + secretKeyPath: configService.get('SECRET_KEY_PATH'), + maxPayloadSize: configService.get('MAX_PAYLOAD_SIZE'), + region: configService.get('S3_REGION'), + bucket: configService.get('S3_BUCKET'), + credentials: { + secretAccessKey: configService.get('S3_SECRET_ACCESS_KEY'), + accessKeyId: configService.get('S3_ACCESS_KEY_ID'), + }, + }; + this.fileStorage = new FileStorageS3(setup, s3StorageConfigFactory); + } + } + + async getSecret(): Promise { + const secretKey = this.configService.get('SECRET_KEY'); + const secretKeyPath = this.configService.get('SECRET_KEY_PATH'); + const secretBase64 = secretKey + ? secretKey + : await this.fileStorage.downloadFile({ + filePath: secretKeyPath, + }); + if (secretBase64?.length) { + return decodeBase64(secretBase64.toString()); + } + return Promise.reject(new Error('Secret file not found')); + } + + setSecret(secret: string): Promise { + if (!isBase64(secret)) { + return Promise.reject(new Error('Secret should be a base64 encoded string')); + } + return this.fileStorage.uploadFile({ + filePath: this.configService.get('SECRET_KEY_PATH'), + content: secret, + }); + } +} +``` + +## Troubleshooting + +If, after upgrading, you get the following error: + +``` +/usr/local/bin/node[57897]: ../src/node_http_parser.cc:517:static void node::(anonymous namespace)::Parser::Execute(const FunctionCallbackInfo &): Assertion `parser->current_buffer_.IsEmpty()' failed. +``` + +You need to update to node v18.6 or higher. This is due to an issue with the node `http` module. +More information can be found [here](https://github.com/nodejs/node/issues/39671) and [here](https://github.com/aws/aws-sdk-js-v3/issues/2843). diff --git a/packages/file-storage/jest.config.ts b/packages/file-storage/jest.config.ts new file mode 100644 index 0000000..a4ffb26 --- /dev/null +++ b/packages/file-storage/jest.config.ts @@ -0,0 +1,19 @@ +/* eslint-disable */ +export default { + displayName: 'nestjs-tools-file-storage', + preset: '../../jest.preset.js', + testEnvironment: 'node', + transform: { + '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }], + }, + moduleFileExtensions: ['ts', 'js', 'html'], + coverageDirectory: '../../coverage/packages/file-storage', + coverageThreshold: { + global: { + statements: 35, + branches: 10, + functions: 15, + lines: 30, + }, + }, +}; diff --git a/packages/file-storage/package.json b/packages/file-storage/package.json new file mode 100644 index 0000000..65560b4 --- /dev/null +++ b/packages/file-storage/package.json @@ -0,0 +1,30 @@ +{ + "name": "@getlarge/nestjs-tools-file-storage", + "version": "0.8.0", + "description": "File Storage Juggler", + "keywords": [ + "file", + "storage", + "s3", + "aws", + "FileStorage", + "nestjs" + ], + "license": "Apache-2.0", + "author": "Edouard Maleix ", + "homepage": "https://github.com/getlarge/nestjs-tools/tree/main/packages/file-storage", + "publishConfig": { + "registry": "https://registry.npmjs.org/" + }, + "publicConfig": { + "access": "public" + }, + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@aws-sdk/client-s3": "3", + "@aws-sdk/lib-storage": "3", + "@nestjs/common": "10" + } +} diff --git a/packages/file-storage/project.json b/packages/file-storage/project.json new file mode 100644 index 0000000..a51e423 --- /dev/null +++ b/packages/file-storage/project.json @@ -0,0 +1,20 @@ +{ + "name": "nestjs-tools-file-storage", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "packages/file-storage/src", + "projectType": "library", + "tags": [], + "targets": { + "build": { + "executor": "@nx/js:tsc", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/packages/file-storage", + "tsConfig": "packages/file-storage/tsconfig.lib.json", + "packageJson": "packages/file-storage/package.json", + "main": "packages/file-storage/src/index.ts", + "assets": ["packages/file-storage/*.md"] + } + } + } +} diff --git a/packages/file-storage/src/index.ts b/packages/file-storage/src/index.ts new file mode 100644 index 0000000..a5e987a --- /dev/null +++ b/packages/file-storage/src/index.ts @@ -0,0 +1,8 @@ +export * from './lib/constants'; +export * from './lib/file-storage.class'; +export * from './lib/file-storage.module'; +export * from './lib/file-storage.service'; +export * from './lib/file-storage-fs.class'; +export * from './lib/file-storage-s3.class'; +export * from './lib/inject-file-storage.decorator'; +export * from './lib/types'; diff --git a/packages/file-storage/src/lib/constants.ts b/packages/file-storage/src/lib/constants.ts new file mode 100644 index 0000000..a3257ea --- /dev/null +++ b/packages/file-storage/src/lib/constants.ts @@ -0,0 +1 @@ +export const FILE_STORAGE_STRATEGY_TOKEN = Symbol('__file_storage_strategy__'); diff --git a/packages/file-storage/src/lib/file-storage-fs.class.ts b/packages/file-storage/src/lib/file-storage-fs.class.ts new file mode 100644 index 0000000..6510921 --- /dev/null +++ b/packages/file-storage/src/lib/file-storage-fs.class.ts @@ -0,0 +1,185 @@ +import { + BigIntOptions, + createReadStream, + createWriteStream, + existsSync, + mkdirSync, + ObjectEncodingOptions, + stat, + StatOptions, + unlink, + WriteFileOptions, +} from 'fs'; +import { readdir, readFile, rm, writeFile } from 'node:fs/promises'; +import { resolve as resolvePath } from 'node:path'; +import { finished, Readable } from 'node:stream'; + +import { + FileStorage, + FileStorageBaseArgs, + FileStorageConfig, + FileStorageConfigFactory, + FileStorageDirBaseArgs, +} from './file-storage.class'; +import { FileStorageWritable, MethodTypes, Request } from './types'; + +export type StreamOptions = { + flags?: string; + encoding?: BufferEncoding; + fd?: number; + mode?: number; + autoClose?: boolean; + emitClose?: boolean; + start?: number; + end?: number; + highWaterMark?: number; +}; + +export type FileStorageLocalSetup = { + storagePath: string; + maxPayloadSize: number; + [key: string]: unknown; +}; + +function config(setup: FileStorageLocalSetup) { + const { maxPayloadSize, storagePath } = setup; + const filePath = (options: { req?: Request; methodType: MethodTypes; fileName: string }): string => { + const { fileName, methodType } = options; + if (!existsSync(storagePath) && methodType === MethodTypes.WRITE) { + mkdirSync(storagePath, { recursive: true }); + } + return resolvePath(storagePath, fileName); + }; + const limits = { fileSize: maxPayloadSize * 1024 * 1024 }; + return { filePath, limits }; +} + +export interface FileStorageLocalFileExists extends FileStorageBaseArgs { + options?: StatOptions | BigIntOptions; +} + +export interface FileStorageLocalUploadFile extends FileStorageBaseArgs { + content: string | Uint8Array | Buffer; + options?: WriteFileOptions; +} + +export interface FileStorageLocalUploadStream extends FileStorageBaseArgs { + options?: BufferEncoding | StreamOptions; +} + +export interface FileStorageLocalDownloadFile extends FileStorageBaseArgs { + options: + | { encoding?: null; flag?: string } + | { encoding: BufferEncoding; flag?: string } + | BufferEncoding + | (ObjectEncodingOptions & { flag?: string }) + | undefined + | null; + // options?: Record | BufferEncoding | null; +} + +export interface FileStorageLocalDownloadStream extends FileStorageBaseArgs { + options?: BufferEncoding | StreamOptions; +} + +// TODO: control filesize limit +export class FileStorageLocal implements FileStorage { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + readonly config: FileStorageConfig & Record; + + constructor( + setup: FileStorageLocalSetup, + factory?: FileStorageConfigFactory, + ) { + this.config = typeof factory === 'function' ? factory(setup) : config(setup); + } + + transformFilePath( + fileName: string, + methodType: MethodTypes, + request?: Request, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + options: any = {}, + ): string | Promise { + return typeof this.config.filePath === 'function' + ? this.config.filePath({ fileName, request, methodType, ...options }) + : fileName; + } + + async fileExists(args: FileStorageLocalFileExists): Promise { + const { filePath, options = {}, request } = args; + const fileName = await this.transformFilePath(filePath, MethodTypes.READ, request, options); + return new Promise((resolve, reject) => stat(fileName, (err) => (err ? reject(err) : resolve(true)))); + } + + async uploadFile(args: FileStorageLocalUploadFile): Promise { + const { filePath, content, options, request } = args; + const fileName = await this.transformFilePath(filePath, MethodTypes.WRITE, request, options); + return writeFile(fileName, content, options); + } + + async uploadStream(args: FileStorageLocalUploadStream): Promise { + const { filePath, options, request } = args; + const fileName = await this.transformFilePath(filePath, MethodTypes.WRITE, request, options); + const writeStream = createWriteStream(fileName, options); + finished(writeStream, (err) => writeStream.emit('done', err)); + return writeStream; + } + + downloadFile(args: { + filePath: string; + options: { encoding?: null; flag?: string }; + request?: Request; + }): Promise; + downloadFile(args: { + filePath: string; + options: { encoding: BufferEncoding; flag?: string } | BufferEncoding; + request?: Request; + }): Promise; + downloadFile(args: { + filePath: string; + options: (ObjectEncodingOptions & { flag?: string }) | BufferEncoding | undefined | null; + request?: Request; + }): Promise; + downloadFile(args: { filePath: string; request?: Request }): Promise; + async downloadFile(args: FileStorageLocalDownloadFile) { + const { filePath, options, request } = args; + const fileName = await this.transformFilePath(filePath, MethodTypes.READ, request, options); + return readFile(fileName, options); + } + + async downloadStream(args: FileStorageLocalDownloadStream): Promise { + const { filePath, options, request } = args; + const fileName = await this.transformFilePath(filePath, MethodTypes.READ, request, options); + return createReadStream(fileName, options); + } + + async deleteFile(args: FileStorageBaseArgs): Promise { + const { filePath, request } = args; + const fileName = await this.transformFilePath(filePath, MethodTypes.DELETE, request); + return new Promise((resolve, reject) => + unlink(fileName, (err) => (err && err.message === 'EENOENT' ? reject(err) : resolve(true))), + ); + } + + async deleteDir(args: FileStorageDirBaseArgs): Promise { + const { dirPath, request } = args; + const dirName = await this.transformFilePath(dirPath, MethodTypes.DELETE, request); + return rm(dirName, { recursive: true, force: true }); + } + + // TODO: indicate if the item is a file or a directory + async readDir(args: FileStorageDirBaseArgs): Promise { + const { dirPath, request } = args; + try { + const transformedDirPath = await this.transformFilePath(dirPath, MethodTypes.READ, request); + // we need return await to catch the error + return await readdir(transformedDirPath); + } catch (err) { + if (err instanceof Error && 'code' in err && err['code'] === 'ENOENT') { + return []; + } + throw err; + } + } +} diff --git a/packages/file-storage/src/lib/file-storage-s3.class.ts b/packages/file-storage/src/lib/file-storage-s3.class.ts new file mode 100644 index 0000000..e660a18 --- /dev/null +++ b/packages/file-storage/src/lib/file-storage-s3.class.ts @@ -0,0 +1,264 @@ +import { + DeleteObjectCommandInput, + DeleteObjectsCommandInput, + GetObjectCommandInput, + HeadObjectCommandInput, + ListObjectsV2CommandInput, + PutObjectCommandInput, + S3, +} from '@aws-sdk/client-s3'; +import { Upload } from '@aws-sdk/lib-storage'; +import { PassThrough, Readable } from 'node:stream'; + +import { + FileStorage, + FileStorageBaseArgs, + FileStorageConfig, + FileStorageConfigFactory, + FileStorageDirBaseArgs, +} from './file-storage.class'; +import { FileStorageWritable, MethodTypes, Request } from './types'; + +/** + * Either region or endpoint must be provided + */ +export type FileStorageS3Setup = { + bucket: string; + maxPayloadSize: number; + credentials?: { + accessKeyId: string; + secretAccessKey: string; + }; + logger?: S3['config']['logger']; + [key: string]: unknown; +} & ({ region: string; endpoint?: never } | { endpoint: string; region?: never }); + +export interface FileStorageS3Config { + s3: S3; + bucket: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + [key: string]: any; +} + +function config(setup: FileStorageS3Setup) { + const { bucket, maxPayloadSize, credentials, endpoint, logger } = setup; + const region = setup.region ?? FileStorageS3.extractRegionFromEndpoint(endpoint ?? ''); + if (!region) { + throw new Error('AWS region is missing'); + } + const s3 = new S3({ + /** + * We cannot really make calls without credentials unless we use a workaround + * @see https://github.com/aws/aws-sdk-js-v3/issues/2321 + */ + ...(credentials ? { credentials } : {}), + region, + ...(logger ? { logger } : {}), + }); + + const filePath = (options: { request?: Request; fileName: string }): string => { + const { fileName } = options; + return `public/${fileName}`; + }; + const limits = { fileSize: maxPayloadSize * 1024 * 1024 }; + return { + s3, + bucket, + filePath, + limits, + }; +} + +export interface FileStorageS3FileExists extends FileStorageBaseArgs { + options?: HeadObjectCommandInput; +} + +export interface FileStorageS3UploadFile extends FileStorageBaseArgs { + content: string | Uint8Array | Buffer; + options?: PutObjectCommandInput; +} + +export interface FileStorageS3UploadStream extends FileStorageBaseArgs { + options?: PutObjectCommandInput; +} + +export interface FileStorageS3DownloadFile extends FileStorageBaseArgs { + options?: GetObjectCommandInput; +} + +export interface FileStorageS3DownloadStream extends FileStorageBaseArgs { + options?: GetObjectCommandInput; +} + +export interface FileStorageS3DeleteFile extends FileStorageBaseArgs { + options?: DeleteObjectCommandInput; +} + +function removeTrailingForwardSlash(x?: string) { + return x?.endsWith('/') ? x?.slice(0, -1) : x; +} + +function addTrailingForwardSlash(x: string) { + return x.endsWith('/') ? x : `${x}/`; +} + +// TODO: control filesize limit +export class FileStorageS3 implements FileStorage { + readonly config: FileStorageConfig & FileStorageS3Config; + + constructor(setup: FileStorageS3Setup, factory?: FileStorageConfigFactory) { + this.config = typeof factory === 'function' ? factory(setup) : config(setup); + } + + static extractRegionFromEndpoint(endpoint: string): string | null { + const match = endpoint?.match(/(?<=\.)[^.]+(?=\.amazonaws\.com)/); + return match?.length ? match[0] : null; + } + + transformFilePath( + fileName: string, + methodType: MethodTypes, + request?: Request, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + options: any = {}, + ): string | Promise { + return typeof this.config.filePath === 'function' + ? this.config.filePath({ fileName, methodType, request, ...options }) + : fileName; + } + + async fileExists(args: FileStorageS3FileExists): Promise { + const { filePath, options = {}, request } = args; + const { s3, bucket: Bucket } = this.config; + const Key = await this.transformFilePath(filePath, MethodTypes.READ, request, options); + await s3.headObject({ Key, Bucket, ...options }); + return true; + } + + async uploadFile(args: FileStorageS3UploadFile): Promise { + const { filePath, content, options = {}, request } = args; + const { s3, bucket: Bucket } = this.config; + const Key = await this.transformFilePath(filePath, MethodTypes.WRITE, request, options); + await new Upload({ + client: s3, + params: { Bucket, Key, Body: content, ...options }, + }).done(); + } + + async uploadStream(args: FileStorageS3UploadStream): Promise { + const { filePath, options = {}, request } = args; + const Key = await this.transformFilePath(filePath, MethodTypes.WRITE, request, options); + const { s3, bucket: Bucket } = this.config; + const writeStream = new PassThrough(); + new Upload({ + client: s3, + params: { + Body: writeStream, + Key, + Bucket, + ...options, + }, + }) + .done() + .then(() => { + writeStream.emit('done'); + }) + .catch((err) => { + writeStream.emit('done', err); + }); + return writeStream; + } + + async downloadFile(args: FileStorageS3DownloadFile): Promise { + const { filePath, options = {}, request } = args; + const Key = await this.transformFilePath(filePath, MethodTypes.READ, request, options); + const { s3, bucket: Bucket } = this.config; + const readable = (await s3.getObject({ Bucket, Key, ...options })).Body as Readable; + const chunks: Buffer[] = []; + for await (const chunk of readable) { + chunks.push(chunk); + } + return Buffer.concat(chunks); + } + + async downloadStream(args: FileStorageS3DownloadStream): Promise { + const { filePath, options = {}, request } = args; + const Key = await this.transformFilePath(filePath, MethodTypes.READ, request, options); + const { s3, bucket: Bucket } = this.config; + const object = await s3.getObject({ Bucket, Key, ...options }); + // from https://github.com/aws/aws-sdk-js-v3/issues/1877#issuecomment-755446927 + return object.Body as Readable; + } + + async deleteFile(args: FileStorageS3DeleteFile): Promise { + const { filePath, options = {}, request } = args; + const Key = await this.transformFilePath(filePath, MethodTypes.DELETE, request, options); + const { s3, bucket: Bucket } = this.config; + await s3.deleteObject({ Bucket, Key, ...options }); + return true; + } + + async deleteDir(args: FileStorageDirBaseArgs): Promise { + const { dirPath, request } = args; + const { s3, bucket: Bucket } = this.config; + const listKey = await this.transformFilePath(dirPath, MethodTypes.DELETE, request); + const listParams: ListObjectsV2CommandInput = { + Bucket, + Prefix: listKey, + }; + // get list of objects in a dir + const listedObjects = await s3.listObjectsV2(listParams); + if (!listedObjects.Contents?.length) { + return; + } + + const deleteParams: DeleteObjectsCommandInput = { + Bucket, + Delete: { + Objects: listedObjects.Contents.map(({ Key }) => ({ + Key, + })), + }, + }; + await s3.deleteObjects(deleteParams); + + if (listedObjects.IsTruncated) { + await this.deleteDir({ dirPath }); + } + } + + // TODO: indicate if the item is a file or a directory + async readDir(args: FileStorageDirBaseArgs): Promise { + const { dirPath, request } = args; + const { s3, bucket: Bucket } = this.config; + const Key = await this.transformFilePath(dirPath, MethodTypes.READ, request); + const listParams: ListObjectsV2CommandInput = { + Bucket, + Delimiter: '/', + }; + // Passing in / as Key breaks the folder matching + if (Key !== '/' && Key !== '') { + listParams.Prefix = addTrailingForwardSlash(Key); + } + const listedObjects = await s3.listObjectsV2(listParams); + const filesAndFilders = []; + // add nested folders, CommonPrefixes contains / + if (listedObjects.CommonPrefixes?.length) { + const folders = listedObjects.CommonPrefixes.map((prefixObject) => { + const prefix = removeTrailingForwardSlash(prefixObject.Prefix) ?? ''; + const key = listParams['Prefix']; + // If key exists, we are looking for a nested folder + return key ? prefix.slice(key.length) : prefix; + }); + filesAndFilders.push(...folders); + } + // adds filenames + if (listedObjects.Contents?.length && listedObjects.Prefix) { + const files = listedObjects.Contents.filter((file) => !!file.Key).map((file) => + file.Key?.replace(listedObjects.Prefix as string, ''), + ) as string[]; + filesAndFilders.push(...files); + } + return filesAndFilders; + } +} diff --git a/packages/file-storage/src/lib/file-storage.class.ts b/packages/file-storage/src/lib/file-storage.class.ts new file mode 100644 index 0000000..05edb01 --- /dev/null +++ b/packages/file-storage/src/lib/file-storage.class.ts @@ -0,0 +1,96 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import type { Readable } from 'node:stream'; + +import { FileStorageWritable, MethodTypes, Request } from './types'; + +export interface FileStorageConfig { + filePath?: (options: { + request?: Request; + fileName: string; + methodType: MethodTypes; + [key: string]: unknown; + }) => string | Promise; + limits?: { fileSize: number }; +} + +export type FileStorageConfigFactory, S extends Record> = ( + setup: S, +) => T & FileStorageConfig; + +const defaultErrorMessage = 'Funtion must be implemented'; + +export interface FileStorageBaseArgs { + filePath: string; + request?: Request; +} + +export interface FileStorageDirBaseArgs { + dirPath: string; + request?: Request; +} + +export type FileStorageTransformPath = ( + fileName: string, + methodType: MethodTypes, + request?: Request, + options?: any, +) => string | Promise; + +export abstract class FileStorage { + readonly config?: FileStorageConfig & Record; + + transformFilePath: FileStorageTransformPath = ( + fileName, + methodType, + request, + options = {}, + ): string | Promise => { + throw new Error(defaultErrorMessage); + }; + + fileExists(args: FileStorageBaseArgs & { options?: string | any }): Promise { + throw new Error(defaultErrorMessage); + } + + uploadFile( + args: FileStorageBaseArgs & { + content: Buffer | Uint8Array | string; + options?: string | any; + }, + ): Promise { + throw new Error(defaultErrorMessage); + } + + uploadStream( + args: FileStorageBaseArgs & { + options?: string | any; + }, + ): Promise { + throw new Error(defaultErrorMessage); + } + + downloadFile(args: FileStorageBaseArgs & { options?: string | any }): Promise { + throw new Error(defaultErrorMessage); + } + + downloadStream( + args: FileStorageBaseArgs & { + options?: string | any; + }, + ): Promise { + throw new Error(defaultErrorMessage); + } + + deleteFile(args: FileStorageBaseArgs): Promise { + throw new Error(defaultErrorMessage); + } + + deleteDir(args: FileStorageDirBaseArgs): Promise { + throw new Error(defaultErrorMessage); + } + + readDir(args: FileStorageDirBaseArgs): Promise { + throw new Error(defaultErrorMessage); + } +} diff --git a/packages/file-storage/src/lib/file-storage.module.ts b/packages/file-storage/src/lib/file-storage.module.ts new file mode 100644 index 0000000..cb83f57 --- /dev/null +++ b/packages/file-storage/src/lib/file-storage.module.ts @@ -0,0 +1,92 @@ +import { DynamicModule, Module, Provider } from '@nestjs/common'; + +import { FILE_STORAGE_STRATEGY_TOKEN } from './constants'; +import { FileStorage } from './file-storage.class'; +import { FileStorageService } from './file-storage.service'; +import { FileStorageLocal } from './file-storage-fs.class'; +import { FileStorageS3, FileStorageS3Setup } from './file-storage-s3.class'; +import { + FileStorageLocalOptions, + FileStorageModuleAsyncOptions, + FileStorageModuleOptions, + FileStorageS3Options, + StorageType, +} from './types'; + +export function getFileStorageStrategy>( + storageType: S, + config: FileStorageModuleOptions[S], +): FileStorageLocal | FileStorageS3; +export function getFileStorageStrategy< + S extends StorageType = StorageType.FS, + E extends Record = Record, +>(storageType: S, config: FileStorageModuleOptions[S]): FileStorageLocal; +export function getFileStorageStrategy< + S extends StorageType = StorageType.S3, + E extends Record = Record, +>(storageType: S, config: FileStorageModuleOptions[S]): FileStorageS3; +export function getFileStorageStrategy>( + storageType: S, + config: FileStorageModuleOptions[S], +): FileStorageLocal | FileStorageS3 { + const { setup, factory } = config as FileStorageModuleOptions[S]; + if (storageType === StorageType.FS) { + return new FileStorageLocal( + setup as FileStorageLocalOptions['setup'], + factory as FileStorageLocalOptions['factory'], + ); + } + return new FileStorageS3(setup as FileStorageS3Setup, factory as FileStorageS3Options['factory']); +} + +@Module({}) +export class FileStorageModule { + public static forRoot( + storageType: StorageType.FS | StorageType.S3, + options: Partial>> = { + [StorageType.FS]: { setup: { storagePath: 'store', maxPayloadSize: 1 } }, + }, + isGlobal?: boolean, + ): DynamicModule { + if (!(storageType in options)) { + throw new TypeError(`${storageType} options is missing.`); + } + const fileStorage = getFileStorageStrategy( + storageType, + options[storageType] as FileStorageModuleOptions>[StorageType], + ); + const providers: [Provider, Provider] = [ + { + provide: FILE_STORAGE_STRATEGY_TOKEN, + useValue: fileStorage, + }, + FileStorageService, + ]; + return { + module: FileStorageModule, + global: isGlobal, + providers, + exports: providers, + }; + } + + public static forRootAsync(options: FileStorageModuleAsyncOptions, isGlobal?: boolean): DynamicModule { + const { inject = [], imports = [], useFactory } = options; + const providers: [Provider>, Provider] = [ + { + provide: FILE_STORAGE_STRATEGY_TOKEN, + useFactory, + inject, + }, + FileStorageService, + ]; + + return { + module: FileStorageModule, + global: isGlobal, + imports, + providers, + exports: providers, + }; + } +} diff --git a/packages/file-storage/src/lib/file-storage.service.ts b/packages/file-storage/src/lib/file-storage.service.ts new file mode 100644 index 0000000..9eb2a99 --- /dev/null +++ b/packages/file-storage/src/lib/file-storage.service.ts @@ -0,0 +1,58 @@ +import { Injectable } from '@nestjs/common'; +import type { Readable } from 'node:stream'; + +import { FileStorage, FileStorageBaseArgs, FileStorageDirBaseArgs } from './file-storage.class'; +import { + FileStorageLocalDownloadFile, + FileStorageLocalDownloadStream, + FileStorageLocalFileExists, + FileStorageLocalUploadFile, + FileStorageLocalUploadStream, +} from './file-storage-fs.class'; +import { + FileStorageS3DeleteFile, + FileStorageS3DownloadFile, + FileStorageS3DownloadStream, + FileStorageS3FileExists, + FileStorageS3UploadFile, + FileStorageS3UploadStream, +} from './file-storage-s3.class'; +import { InjectFileStorageStrategy } from './inject-file-storage.decorator'; +import type { FileStorageWritable } from './types'; + +@Injectable() +export class FileStorageService implements Omit { + constructor(@InjectFileStorageStrategy() private readonly fileStorage: FileStorage) {} + + fileExists(args: FileStorageLocalFileExists | FileStorageS3FileExists): Promise { + return this.fileStorage.fileExists(args); + } + + uploadFile(args: FileStorageLocalUploadFile | FileStorageS3UploadFile): Promise { + return this.fileStorage.uploadFile(args); + } + + uploadStream(args: FileStorageLocalUploadStream | FileStorageS3UploadStream): Promise { + return this.fileStorage.uploadStream(args); + } + + downloadFile(args: FileStorageLocalDownloadFile | FileStorageS3DownloadFile): Promise { + return this.fileStorage.downloadFile(args); + } + + downloadStream(args: FileStorageLocalDownloadStream | FileStorageS3DownloadStream): Promise { + return this.fileStorage.downloadStream(args); + } + + deleteFile(args: FileStorageBaseArgs | FileStorageS3DeleteFile): Promise { + return this.fileStorage.deleteFile(args); + } + + readDir(args: FileStorageDirBaseArgs): Promise { + return this.fileStorage.readDir(args); + } + + deleteDir(args: FileStorageDirBaseArgs): Promise { + return this.fileStorage.deleteDir(args); + } +} diff --git a/packages/file-storage/src/lib/inject-file-storage.decorator.ts b/packages/file-storage/src/lib/inject-file-storage.decorator.ts new file mode 100644 index 0000000..50b164f --- /dev/null +++ b/packages/file-storage/src/lib/inject-file-storage.decorator.ts @@ -0,0 +1,5 @@ +import { Inject } from '@nestjs/common'; + +import { FILE_STORAGE_STRATEGY_TOKEN } from './constants'; + +export const InjectFileStorageStrategy = () => Inject(FILE_STORAGE_STRATEGY_TOKEN); diff --git a/packages/file-storage/src/lib/types.ts b/packages/file-storage/src/lib/types.ts new file mode 100644 index 0000000..67560b5 --- /dev/null +++ b/packages/file-storage/src/lib/types.ts @@ -0,0 +1,55 @@ +import { InjectionToken, ModuleMetadata } from '@nestjs/common'; +import { Writable } from 'node:stream'; + +import { FileStorage, FileStorageConfigFactory } from './file-storage.class'; +import { FileStorageLocalSetup } from './file-storage-fs.class'; +import { FileStorageS3Config, FileStorageS3Setup } from './file-storage-s3.class'; + +export enum StorageType { + FS = 'FS', + S3 = 'S3', +} + +export enum MethodTypes { + READ = 'read', + WRITE = 'write', + DELETE = 'delete', +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type Request = any; + +export interface FileStorageLocalOptions> { + setup: FileStorageLocalSetup; + factory?: FileStorageConfigFactory; +} + +export interface FileStorageS3Options> { + setup: FileStorageS3Setup; + factory?: FileStorageConfigFactory; +} + +export type FileStorageModuleOptions = Record> = { + [StorageType.FS]: FileStorageLocalOptions; + [StorageType.S3]: FileStorageS3Options; +}; + +export interface FileStorageModuleAsyncOptions extends Pick { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + useFactory: (...args: any[]) => Promise | FileStorage; + // useClass?: FileStorage; + // useExisting?: FileStorage; + inject?: InjectionToken[]; +} + +interface WritableWithDoneEvent { + emit(event: 'done', error?: Error): boolean; + addListener(event: 'done', listener: (error?: Error) => void): this; + on(event: 'done', listener: (error?: Error) => void): this; + once(event: 'done', listener: (error?: Error) => void): this; + prependOnceListener(event: 'done', listener: (error?: Error) => void): this; + prependListener(event: 'done', listener: (error?: Error) => void): this; + removeListener(event: 'done', listener: () => void): this; +} + +export type FileStorageWritable = Writable & WritableWithDoneEvent; diff --git a/packages/file-storage/test/file-storage.e2e-spec.ts b/packages/file-storage/test/file-storage.e2e-spec.ts new file mode 100644 index 0000000..54752c1 --- /dev/null +++ b/packages/file-storage/test/file-storage.e2e-spec.ts @@ -0,0 +1,164 @@ +/* eslint-disable max-nested-callbacks */ +/* eslint-disable max-lines-per-function */ +import { Test, TestingModule } from '@nestjs/testing'; +import * as dotenv from 'dotenv'; +import { mkdir, rm } from 'node:fs/promises'; +import { resolve } from 'node:path'; +import { once, Readable } from 'node:stream'; +import { pipeline } from 'node:stream/promises'; + +import { FileStorage, FileStorageModule, FileStorageModuleOptions, StorageType } from '../src'; +import { FILE_STORAGE_STRATEGY_TOKEN } from '../src/lib/constants'; + +dotenv.config({ path: resolve(__dirname, '../.env.test') }); + +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace NodeJS { + interface ProcessEnv { + S3_BUCKET: string; + S3_REGION: string; + S3_ACCESS_KEY_ID: string; + S3_SECRET_ACCESS_KEY: string; + S3_ENDPOINT: string; + } + } +} + +const storagePath = 'store'; +const path = resolve(storagePath); +const testFileName = 'test.txt'; +const testFileContent = 'this is a test'; +const dirPath = ''; +const nestedDir = 'nested'; +const nestedFileName = 'nested.txt'; +const nestedFilePath = `${path}/${nestedDir}`; + +const testMap: { + description: string; + storageType: StorageType; + options: Partial; +}[] = [ + { + description: 'file-storage-fs', + storageType: StorageType.FS, + options: { + [StorageType.FS]: { setup: { storagePath, maxPayloadSize: 1 } }, + }, + }, + { + description: 'file-storage-S3', + storageType: StorageType.S3, + options: { + [StorageType.S3]: { + setup: { + storagePath, + maxPayloadSize: 1, + bucket: process.env.S3_BUCKET, + region: process.env.S3_REGION, + credentials: { + accessKeyId: process.env.S3_ACCESS_KEY_ID, + secretAccessKey: process.env.S3_SECRET_ACCESS_KEY, + }, + }, + }, + }, + }, +]; + +testMap.forEach((testSuite) => { + const { description, storageType, options } = testSuite; + + describe(description, () => { + let fileStorage: FileStorage; + + beforeAll(async () => { + const module: TestingModule = await Test.createTestingModule({ + imports: [FileStorageModule.forRoot(storageType, options)], + }).compile(); + + fileStorage = module.get(FILE_STORAGE_STRATEGY_TOKEN); + if (storageType === StorageType.FS) await mkdir(path, { recursive: true }); + // ensure S3 bucket is empty + if (storageType === StorageType.S3) await fileStorage.deleteDir({ dirPath }); + }); + + afterAll(async () => { + if (storageType === StorageType.FS) await rm(path, { recursive: true, force: true }); + if (storageType === StorageType.S3) await fileStorage.deleteDir({ dirPath }); + }); + + it('readDir returns an empty array when no files exist', async () => { + const res = await fileStorage.readDir({ dirPath }); + expect(res.length).toBe(0); + }); + + it('uploadFile uploads a file', async () => { + await fileStorage.uploadFile({ filePath: testFileName, content: 'this is a test' }); + const result = await fileStorage.readDir({ dirPath }); + expect(result.length).toBe(1); + expect(result[0]).toBe(testFileName); + }); + + it('calling fileExists on a filepath that exists returns true', async () => { + const fileExists = await fileStorage.fileExists({ filePath: testFileName }); + expect(fileExists).toBe(true); + }); + + it('calling fileExists on a filepath that doesnt exist throws an error', async () => { + await expect(fileStorage.fileExists({ filePath: 'fileDoesntExist' })).rejects.toThrow(); + }); + + it('deleteFile deletes a file', async () => { + await fileStorage.deleteFile({ filePath: testFileName }); + const result = await fileStorage.readDir({ dirPath }); + expect(result.length).toBe(0); + }); + + it('uploadStream uploads a file', async () => { + const upload = await fileStorage.uploadStream({ filePath: testFileName }); + const entry = Readable.from(Buffer.from(testFileContent)); + const ac = new AbortController(); + const t = setTimeout(() => ac.abort(), 300); + const listener = once(upload, 'done', { signal: ac.signal }); + await pipeline(entry, upload); + await listener.finally(() => clearTimeout(t)); + const result = await fileStorage.readDir({ dirPath }); + expect(result.length).toBe(1); + }); + + it('downloadFile downloads a file', async () => { + const file = await fileStorage.downloadFile({ filePath: testFileName }); + expect(file.toString()).toBe(testFileContent); + }); + + it('downloadStream downloads a file', async () => { + const download = await fileStorage.downloadStream({ filePath: testFileName }); + expect(download).toBeInstanceOf(Readable); + // this makes the assumption that the stream is readable and all the data is available in one read + for await (const chunk of download) { + expect(chunk.toString()).toBe(testFileContent); + } + }); + + it('uploads a file to a nested folder', async () => { + if (storageType === StorageType.FS) await mkdir(nestedFilePath, { recursive: true }); + + await fileStorage.uploadFile({ filePath: `${nestedDir}/${nestedFileName}`, content: 'this is a nested file' }); + const result = await fileStorage.readDir({ dirPath: nestedDir }); + expect(result.length).toBe(1); + expect(result[0]).toBe(nestedFileName); + }); + + it('readDir returns an array of files and folders in a dir', async () => { + const result = await fileStorage.readDir({ dirPath }); + expect(result.length).toBe(2); + expect(result).toEqual([nestedDir, testFileName]); + }); + + it('deleteDir deletes a dir', async () => { + await fileStorage.deleteDir({ dirPath }); + expect(await fileStorage.readDir({ dirPath })).toEqual([]); + }); + }); +}); diff --git a/packages/file-storage/test/file-storage.module.spec.ts b/packages/file-storage/test/file-storage.module.spec.ts new file mode 100644 index 0000000..23ecf4c --- /dev/null +++ b/packages/file-storage/test/file-storage.module.spec.ts @@ -0,0 +1,129 @@ +/* eslint-disable max-lines-per-function */ +import { Test, TestingModule } from '@nestjs/testing'; + +import { + FileStorage, + FileStorageLocal, + FileStorageModule, + FileStorageModuleOptions, + FileStorageS3, + FileStorageService, + StorageType, +} from '../src'; +import { FILE_STORAGE_STRATEGY_TOKEN } from '../src/lib/constants'; + +class FileStorageTest extends FileStorage { + constructor() { + super(); + } +} + +describe('forRootAsync', () => { + it('Can create FileStorage instance with provider method', async () => { + const module: TestingModule = await Test.createTestingModule({ + imports: [ + FileStorageModule.forRootAsync({ + useFactory: (): FileStorageTest => new FileStorageTest(), + }), + ], + }).compile(); + + const fileStorage = module.get(FILE_STORAGE_STRATEGY_TOKEN); + const fileStorageService = module.get(FileStorageService); + + expect(fileStorage).toBeInstanceOf(FileStorage); + expect(fileStorageService).toBeInstanceOf(FileStorageService); + }); + + it('Can create FileStorage instance with async provider method', async () => { + const module: TestingModule = await Test.createTestingModule({ + imports: [ + FileStorageModule.forRootAsync({ + useFactory: async (): Promise => { + await new Promise((resolve) => setTimeout(resolve, 100)); + return new FileStorageTest(); + }, + }), + ], + }).compile(); + + const fileStorage = module.get(FILE_STORAGE_STRATEGY_TOKEN); + const fileStorageService = module.get(FileStorageService); + + expect(fileStorage).toBeInstanceOf(FileStorage); + expect(fileStorageService).toBeInstanceOf(FileStorageService); + }); +}); + +describe('forRoot', () => { + it('Can create FileStorageLocal instance from options', async () => { + const storageType: StorageType = StorageType.FS; + const options: Partial = { + [storageType]: { setup: { storagePath: '', maxPayloadSize: 1 } }, + }; + + const module: TestingModule = await Test.createTestingModule({ + imports: [FileStorageModule.forRoot(storageType, options)], + }).compile(); + + const fileStorage = module.get(FILE_STORAGE_STRATEGY_TOKEN); + const fileStorageService = module.get(FileStorageService); + + expect(fileStorage).toBeInstanceOf(FileStorageLocal); + expect(fileStorageService).toBeInstanceOf(FileStorageService); + }); + + it('Can create FileStorageS3 instance from options passing a region', async () => { + const storageType: StorageType = StorageType.S3; + const options: Partial = { + [storageType]: { + setup: { + bucket: 'bucket', + credentials: { + accessKeyId: 'access key', + secretAccessKey: 'secret access key', + }, + maxPayloadSize: 1, + region: 'eu-central-1', + }, + }, + }; + + const module: TestingModule = await Test.createTestingModule({ + imports: [FileStorageModule.forRoot(storageType, options)], + }).compile(); + + const fileStorage = module.get(FILE_STORAGE_STRATEGY_TOKEN); + const fileStorageService = module.get(FileStorageService); + + expect(fileStorage).toBeInstanceOf(FileStorageS3); + expect(fileStorageService).toBeInstanceOf(FileStorageService); + }); + + it('Can create FileStorageS3 instance from options passing an endpoint', async () => { + const storageType: StorageType = StorageType.S3; + const options: Partial = { + [storageType]: { + setup: { + bucket: 'bucket', + credentials: { + accessKeyId: 'access key', + secretAccessKey: 'secret access key', + }, + maxPayloadSize: 1, + endpoint: 'https://s3.eu-central-1.amazonaws.com/', + }, + }, + }; + + const module: TestingModule = await Test.createTestingModule({ + imports: [FileStorageModule.forRoot(storageType, options)], + }).compile(); + + const fileStorage = module.get(FILE_STORAGE_STRATEGY_TOKEN); + const fileStorageService = module.get(FileStorageService); + + expect(fileStorage).toBeInstanceOf(FileStorageS3); + expect(fileStorageService).toBeInstanceOf(FileStorageService); + }); +}); diff --git a/packages/file-storage/test/helpers.spec.ts b/packages/file-storage/test/helpers.spec.ts new file mode 100644 index 0000000..fe461d4 --- /dev/null +++ b/packages/file-storage/test/helpers.spec.ts @@ -0,0 +1,29 @@ +import { FileStorageS3 } from '../src/lib/file-storage-s3.class'; + +describe('extractRegionFromEndpoint correctly returns the region or throws an error', () => { + const testStrings = [ + ['s3.us-east-2.amazonaws.com', 'us-east-2'], + ['s3-fips.us-east-2.amazonaws.com', 'us-east-2'], + ['s3.dualstack.us-east-2.amazonaws.com', 'us-east-2'], + ['s3-fips.dualstack.us-east-2.amazonaws.com', 'us-east-2'], + ['account-id.s3-control.us-east-2.amazonaws.com', 'us-east-2'], + ['account-id.s3-control-fips.us-east-2.amazonaws.com', 'us-east-2'], + ['account-id.s3-control.dualstack.us-east-2.amazonaws.com', 'us-east-2'], + ['account-id.s3-control-fips.dualstack.us-east-2.amazonaws.com', 'us-east-2'], + ['s3-accesspoint.us-east-2.amazonaws.com', 'us-east-2'], + ['s3-accesspoint-fips.us-east-2.amazonaws.com', 'us-east-2'], + ['s3-accesspoint.dualstack.us-east-2.amazonaws.com', 'us-east-2'], + ['s3-accesspoint-fips.dualstack.us-east-2.amazonaws.com', 'us-east-2'], + ['s3.eu-central-1.amazonaws.com', 'eu-central-1'], + ]; + + testStrings.forEach(([input, expected]) => { + it(`extractRegionFromEndpoint("${input}") returns "${expected}"`, () => { + expect(FileStorageS3.extractRegionFromEndpoint(input)).toBe(expected); + }); + }); + + it('extractRegionFromEndpoint("s3.amazonaws.com") returns null', () => { + expect(FileStorageS3.extractRegionFromEndpoint('s3.amazonaws.com')).toBe(null); + }); +}); diff --git a/packages/file-storage/tsconfig.json b/packages/file-storage/tsconfig.json new file mode 100644 index 0000000..f5b8565 --- /dev/null +++ b/packages/file-storage/tsconfig.json @@ -0,0 +1,22 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "module": "commonjs", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/packages/file-storage/tsconfig.lib.json b/packages/file-storage/tsconfig.lib.json new file mode 100644 index 0000000..c297a24 --- /dev/null +++ b/packages/file-storage/tsconfig.lib.json @@ -0,0 +1,16 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "declaration": true, + "types": ["node"], + "target": "es2021", + "strictNullChecks": true, + "noImplicitAny": true, + "strictBindCallApply": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src/**/*.ts"], + "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] +} diff --git a/packages/file-storage/tsconfig.spec.json b/packages/file-storage/tsconfig.spec.json new file mode 100644 index 0000000..f6d8ffc --- /dev/null +++ b/packages/file-storage/tsconfig.spec.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"] +} diff --git a/packages/lock/.eslintrc.json b/packages/lock/.eslintrc.json new file mode 100644 index 0000000..69704e6 --- /dev/null +++ b/packages/lock/.eslintrc.json @@ -0,0 +1,33 @@ +{ + "extends": ["../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.json"], + "parser": "jsonc-eslint-parser", + "rules": { + "@nx/dependency-checks": [ + "error", + { + "buildTargets": ["build"], + "checkMissingDependencies": true, + "checkObsoleteDependencies": true, + "checkVersionMismatches": true + } + ] + } + } + ] +} diff --git a/packages/lock/CHANGELOG.md b/packages/lock/CHANGELOG.md new file mode 100644 index 0000000..7bcbe6a --- /dev/null +++ b/packages/lock/CHANGELOG.md @@ -0,0 +1,92 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +# [0.7.0](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-lock@0.6.1...@s1seven/nestjs-tools-lock@0.7.0) (2023-09-04) + +### Features + +- **lock:** allow module to be global ([f956e25](https://github.com/s1seven/nestjs-tools/commit/f956e25f1b871a9c1a71e986118b01e1e8c88bd6)) + +## [0.6.1](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-lock@0.6.0...@s1seven/nestjs-tools-lock@0.6.1) (2022-12-21) + +**Note:** Version bump only for package @s1seven/nestjs-tools-lock + +# [0.6.0](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-lock@0.5.0...@s1seven/nestjs-tools-lock@0.6.0) (2022-09-09) + +### Features + +- **lock:** export LockService ([192ee1a](https://github.com/s1seven/nestjs-tools/commit/192ee1aee3c3ad0878cca115736e731b7cff9d38)) + +# [0.5.0](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-lock@0.4.4...@s1seven/nestjs-tools-lock@0.5.0) (2022-08-09) + +### Features + +- **lock:** update dependencies ([17d414e](https://github.com/s1seven/nestjs-tools/commit/17d414ede087807c776ea0e727c5a16956937a9f)) + +### BREAKING CHANGES + +- **lock:** replace redis and warlock + +## [0.4.4](https://github.com/s1seven/nestjs-tools/compare/@s1seven/nestjs-tools-lock@0.4.3...@s1seven/nestjs-tools-lock@0.4.4) (2022-06-02) + +**Note:** Version bump only for package @s1seven/nestjs-tools-lock + +## 0.4.3 (2022-03-17) + +**Note:** Version bump only for package @s1seven/nestjs-tools-lock + +## [0.4.2](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-lock@0.4.1...@s1seven/microservices-lock@0.4.2) (2022-02-10) + +**Note:** Version bump only for package @s1seven/microservices-lock + +## [0.4.1](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-lock@0.4.0...@s1seven/microservices-lock@0.4.1) (2021-11-30) + +### Bug Fixes + +- **lock:** check that redis connection is initialized ([d40f313](https://github.com/s1seven/microservices-common/commit/d40f313ee6c22f4ca845385b468cef77cbe426ca)) + +# [0.4.0](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-lock@0.3.0...@s1seven/microservices-lock@0.4.0) (2021-11-24) + +### Features + +- **lock:** only init Redis connection on module init ([626ea91](https://github.com/s1seven/microservices-common/commit/626ea9153832201b0e0894656573c93b6a1decec)) + +# [0.3.0](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-lock@0.2.5...@s1seven/microservices-lock@0.3.0) (2021-11-22) + +### Features + +- **lock:** create dynamic module to provide redis options ([5ee3da1](https://github.com/s1seven/microservices-common/commit/5ee3da10b34e832b0727a4db300fced0e29007fd)) + +## [0.2.5](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-lock@0.2.4...@s1seven/microservices-lock@0.2.5) (2021-11-22) + +**Note:** Version bump only for package @s1seven/microservices-lock + +## [0.2.4](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-lock@0.2.3...@s1seven/microservices-lock@0.2.4) (2021-11-22) + +**Note:** Version bump only for package @s1seven/microservices-lock + +## [0.2.3](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-lock@0.2.2...@s1seven/microservices-lock@0.2.3) (2021-10-29) + +**Note:** Version bump only for package @s1seven/microservices-lock + +## [0.2.2](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-lock@0.2.1...@s1seven/microservices-lock@0.2.2) (2021-10-08) + +**Note:** Version bump only for package @s1seven/microservices-lock + +## [0.2.1](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-lock@0.2.0...@s1seven/microservices-lock@0.2.1) (2021-09-20) + +**Note:** Version bump only for package @s1seven/microservices-lock + +# [0.2.0](https://github.com/s1seven/microservices-common/compare/@s1seven/microservices-lock@0.1.0...@s1seven/microservices-lock@0.2.0) (2021-09-06) + +### Features + +- implements OnModuleDestroy in LockService ([eae19ff](https://github.com/s1seven/microservices-common/commit/eae19ff5826c43f7543055fa9f68b3c8b69601b8)) + +# 0.1.0 (2021-09-01) + +### Features + +- create LockService and LockModule ([42213a9](https://github.com/s1seven/microservices-common/commit/42213a93645c06a22c35ae07e0314f74d45aacd0)) diff --git a/packages/lock/README.md b/packages/lock/README.md new file mode 100644 index 0000000..a4110ed --- /dev/null +++ b/packages/lock/README.md @@ -0,0 +1,54 @@ +# Lock + +[![npm][npm-image]][npm-url] + +[npm-image]: https://img.shields.io/npm/v/@getlarge/nestjs-tools-lock.svg?style=flat +[npm-url]: https://npmjs.org/package/@getlarge/nestjs-tools-lock + +The Lock Service produce distributed locks to prevent duplicated/conflicted actions to be executed in a distributed environment. +It is based on [Redlock](https://www.npmjs.com/package/redlock) module. + +## Installation + +```bash +$ npm install --save @getlarge/nestjs-tools-lock +``` + +## Usage + +### Inside a CronJob service + +```ts +import { LockService } from '@getlarge/nestjs-tools-lock'; +import { Inject, Injectable } from '@nestjs/common'; +import { Cron } from '@nestjs/schedule'; + +@Injectable() +export class TasksService implements OnModuleDestroy { + constructor(@Inject(LockService) private lockService: LockService) {} + + onModuleDestroy() { + this.lockService.close(); + } + + // using returned unlock function + @Cron('*/10 * * * * *') + async doThis(): Promise { + const lockKey = 'doThis'; + const { unlock } = await this.lockService.lock(lockKey, 2000); + if (typeof unlock !== 'function') { + return; + } + unlock(); + } + + // using lock id + @Cron('*/10 * * * * *') + async doThat(): Promise { + const lockKey = 'doThat'; + await this.lockService.optimist(lockKey, 2000); + const { lockId } = await this.lockService.lock(lockKey, 2000); + this.lockService.unlock(lockKey, lockId); + } +} +``` diff --git a/packages/lock/jest.config.ts b/packages/lock/jest.config.ts new file mode 100644 index 0000000..6f3bab8 --- /dev/null +++ b/packages/lock/jest.config.ts @@ -0,0 +1,19 @@ +/* eslint-disable */ +export default { + displayName: 'nestjs-tools-lock', + preset: '../../jest.preset.js', + testEnvironment: 'node', + transform: { + '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }], + }, + moduleFileExtensions: ['ts', 'js', 'html'], + coverageDirectory: '../../coverage/packages/lock', + coverageThreshold: { + global: { + statements: 70, + branches: 35, + functions: 60, + lines: 70, + }, + }, +}; diff --git a/packages/lock/package.json b/packages/lock/package.json new file mode 100644 index 0000000..94f18e0 --- /dev/null +++ b/packages/lock/package.json @@ -0,0 +1,30 @@ +{ + "name": "@getlarge/nestjs-tools-lock", + "version": "0.7.0", + "description": "A distributed lock manager for NestJS", + "keywords": [ + "lock", + "distributed", + "redis", + "mutex", + "distributed lock", + "nestjs" + ], + "license": "Apache-2.0", + "author": "Edouard Maleix ", + "homepage": "https://github.com/getlarge/nestjs-tools/tree/main/packages/lock", + "publishConfig": { + "registry": "https://registry.npmjs.org/" + }, + "publicConfig": { + "access": "public" + }, + "dependencies": { + "redlock": "^5.0.0-beta.2", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@nestjs/common": "10", + "ioredis": "^5.3.2" + } +} diff --git a/packages/lock/project.json b/packages/lock/project.json new file mode 100644 index 0000000..e7c7283 --- /dev/null +++ b/packages/lock/project.json @@ -0,0 +1,20 @@ +{ + "name": "nestjs-tools-lock", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "packages/lock/src", + "projectType": "library", + "tags": [], + "targets": { + "build": { + "executor": "@nx/js:tsc", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/packages/lock", + "tsConfig": "packages/lock/tsconfig.lib.json", + "packageJson": "packages/lock/package.json", + "main": "packages/lock/src/index.ts", + "assets": ["packages/lock/*.md"] + } + } + } +} diff --git a/packages/lock/src/index.ts b/packages/lock/src/index.ts new file mode 100644 index 0000000..6ed1f0f --- /dev/null +++ b/packages/lock/src/index.ts @@ -0,0 +1,3 @@ +export * from './lib/constants'; +export * from './lib/lock.module'; +export * from './lib/lock.service'; diff --git a/packages/lock/src/lib/constants.ts b/packages/lock/src/lib/constants.ts new file mode 100644 index 0000000..05c3623 --- /dev/null +++ b/packages/lock/src/lib/constants.ts @@ -0,0 +1 @@ +export const LOCK_SERVICE_OPTIONS = '__lock_service_options__'; diff --git a/packages/lock/src/lib/lock.module.ts b/packages/lock/src/lib/lock.module.ts new file mode 100644 index 0000000..423125e --- /dev/null +++ b/packages/lock/src/lib/lock.module.ts @@ -0,0 +1,59 @@ +import { DynamicModule, InjectionToken, Module, ModuleMetadata, Provider, Type } from '@nestjs/common'; + +import { LOCK_SERVICE_OPTIONS } from './constants'; +import { LockService, LockServiceOptions } from './lock.service'; + +export type Injection = InjectionToken[]; +export interface LockModuleModuleAsyncOptions extends Pick { + name?: string; + useClass?: Type; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + useFactory?: (...args: any[]) => LockServiceOptions; + inject?: Injection; +} + +function getAsyncProviders(options: LockModuleModuleAsyncOptions): Provider[] { + const { inject = [], useFactory, useClass } = options; + if (useFactory && useClass) { + throw new Error('Invalid configuration, useFactory and useClass should not be defined at the same time'); + } + + if (useFactory) { + return [{ provide: LOCK_SERVICE_OPTIONS, useFactory, inject }, LockService]; + } + if (useClass) { + return [{ provide: LOCK_SERVICE_OPTIONS, useClass }, LockService]; + } + throw new Error('Invalid configuration, useFactory or useClass should be defined'); +} + +@Module({}) +export class LockModule { + public static forRoot(options?: LockServiceOptions, isGlobal = false): DynamicModule { + const providers = [ + { + provide: LOCK_SERVICE_OPTIONS, + useValue: options, + }, + LockService, + ]; + return { + global: isGlobal, + module: LockModule, + providers, + exports: providers, + }; + } + + public static forRootAsync(options: LockModuleModuleAsyncOptions, isGlobal = false): DynamicModule { + const { imports = [] } = options; + const providers = getAsyncProviders(options); + return { + global: isGlobal, + module: LockModule, + imports, + providers, + exports: [LockService], + }; + } +} diff --git a/packages/lock/src/lib/lock.service.ts b/packages/lock/src/lib/lock.service.ts new file mode 100644 index 0000000..367f6ea --- /dev/null +++ b/packages/lock/src/lib/lock.service.ts @@ -0,0 +1,90 @@ +import { Inject, Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common'; +import IORedis, { Redis, RedisOptions } from 'ioredis'; +import Redlock, { ExecutionResult, Lock, RedlockAbortSignal, ResourceLockedError, Settings } from 'redlock'; + +import { LOCK_SERVICE_OPTIONS } from './constants'; + +export type LockResponse = { + unlock: () => Promise; + lockId: string; +}; + +export type LockOptions = Partial; + +export interface LockServiceOptions { + redis: RedisOptions; + lock?: LockOptions; +} + +@Injectable() +export class LockService implements OnModuleInit, OnModuleDestroy { + private readonly defaultLockOptions: LockOptions = { + retryCount: 1, + retryDelay: 200, + // automaticExtensionThreshold: 500, + }; + private redis!: Redis; + redlock!: Redlock; + + constructor(@Inject(LOCK_SERVICE_OPTIONS) readonly options: LockServiceOptions) {} + + onModuleInit(): void { + this.createConnection(); + } + + async onModuleDestroy(): Promise { + await this.close(); + } + + errorHandler(error: unknown) { + // Ignore cases where a resource is explicitly marked as locked on a client. + if (error instanceof ResourceLockedError) { + return; + } + // Log all other errors. + console.error(error); + } + + createConnection(): void { + this.redis = new IORedis(this.options.redis); + this.redlock = new Redlock([this.redis], { ...this.defaultLockOptions, ...(this.options.lock || {}) }); + // this.redlock.on('error', this.errorHandler); + } + + isInitialized(): void { + if (!this.redis || !this.redlock) { + throw new Error('Redis was not yet initialized'); + } + } + + optimistic(key: string, ttl: number, cb: (signal: RedlockAbortSignal) => Promise): Promise { + this.isInitialized(); + return this.redlock.using([key], ttl, cb); + } + + lock(key: string, ttl: number): Promise { + this.isInitialized(); + return this.redlock.acquire([key], ttl); + } + + async get(key: string, lockId: string): Promise { + this.isInitialized(); + const value = await this.redis.get(key); + // provide fake data for attempts and expiration as this lock would be used for release only + return value !== lockId ? null : new Lock(this.redlock, [key], lockId, [], 100); + } + + async unlock(key: string, lockId: string): Promise { + this.isInitialized(); + const lock = await this.get(key, lockId); + if (!lock) { + throw new Error(`Lock ${key} - ${lockId} not found.`); + } + return this.redlock.release(lock); + } + + close(): Promise { + this.redlock?.removeAllListeners('error'); + return this.redlock?.quit(); + } +} diff --git a/packages/lock/test/config.service.mock.ts b/packages/lock/test/config.service.mock.ts new file mode 100644 index 0000000..eca472b --- /dev/null +++ b/packages/lock/test/config.service.mock.ts @@ -0,0 +1,60 @@ +import { ConfigService } from '@nestjs/config'; +import type { RedisOptions } from 'ioredis'; + +export const mockConfigService = { + get: (key: string) => { + switch (key) { + case 'REDIS_URL': + return 'redis://localhost:6379/0'; + case 'REDIS_PORT': + return 6379; + case 'REDIS_HOSTNAME': + return 'localhost'; + case 'REDIS_DB': + return 0; + case 'REDIS_PASSWORD': + return process.env['REDIS_PASSWORD'] || ''; + case 'REDIS_USERNAME': + return process.env['REDIS_USERNAME'] || ''; + default: + return undefined; + } + }, +}; + +export function parseRedisUrl(url: string) { + const redisUrl = new URL(url); + return { + protocol: redisUrl.protocol, + port: +redisUrl.port, + host: redisUrl.hostname, + username: redisUrl.username, + password: redisUrl.password, + }; +} + +export function getRedisClientConfig(configService: ConfigService): RedisOptions { + const url = configService.get('REDIS_URL') || ''; + const { port, host, username, password, protocol } = parseRedisUrl(url); + const baseOptions: RedisOptions = { + port: configService.get('REDIS_PORT') || port, + host: configService.get('REDIS_HOSTNAME') || host, + db: configService.get('REDIS_DB'), + ...((configService.get('REDIS_USERNAME') || username) && { + username: configService.get('REDIS_USERNAME') || username, + }), + ...((configService.get('REDIS_PASSWORD') || password) && { + password: configService.get('REDIS_PASSWORD') || password, + }), + retryStrategy(times: number): number { + return Math.min(times * 500, 2000); + }, + reconnectOnError(): boolean | 1 | 2 { + return 1; + }, + }; + if (protocol.startsWith('rediss')) { + baseOptions.tls = { rejectUnauthorized: false }; + } + return baseOptions; +} diff --git a/packages/lock/test/lock.module.spec.ts b/packages/lock/test/lock.module.spec.ts new file mode 100644 index 0000000..5a52c73 --- /dev/null +++ b/packages/lock/test/lock.module.spec.ts @@ -0,0 +1,45 @@ +import { Test, TestingModule } from '@nestjs/testing'; + +import { LOCK_SERVICE_OPTIONS, LockModule, LockService } from '../src'; +import { getRedisClientConfig, mockConfigService } from './config.service.mock'; + +describe('forRootAsync', () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const redis = getRedisClientConfig(mockConfigService as any); + + it('Can create instance with provider method', async () => { + const module: TestingModule = await Test.createTestingModule({ + imports: [ + LockModule.forRootAsync({ + useFactory: () => ({ redis }), + }), + ], + }).compile(); + await module.init(); + + const options = module.get(LOCK_SERVICE_OPTIONS); + expect(options.redis).toHaveProperty('port'); + expect(options.redis.port).toEqual(redis.port); + + await module.close(); + }); +}); + +describe('forRoot', () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const options = getRedisClientConfig(mockConfigService as any); + + it('Can create instance ', async () => { + const module: TestingModule = await Test.createTestingModule({ + imports: [LockModule.forRoot({ redis: options })], + }).compile(); + await module.init(); + + const lockService = module.get(LockService); + expect(lockService).toBeDefined(); + expect(lockService.options).toBeDefined(); + expect(lockService.options.redis.port).toEqual(options.port); + + await module.close(); + }); +}); diff --git a/packages/lock/test/lock.service.spec.ts b/packages/lock/test/lock.service.spec.ts new file mode 100644 index 0000000..a41a1dd --- /dev/null +++ b/packages/lock/test/lock.service.spec.ts @@ -0,0 +1,87 @@ +/* eslint-disable max-lines-per-function */ +import { ExecutionError } from 'redlock'; + +import { LockService } from '../src'; +import { getRedisClientConfig, mockConfigService } from './config.service.mock'; +import { PatchedLockService } from './patched-lock.service.mock'; + +describe('Lock Service', () => { + let lockService: LockService; + + beforeAll(() => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const redis = getRedisClientConfig(mockConfigService as any); + lockService = new PatchedLockService({ redis, lock: { retryCount: 0 } }); + lockService.onModuleInit(); + }); + + afterAll(async () => { + await lockService.onModuleDestroy(); + }); + + it('lock() - sets lock', async () => { + const lock = await lockService.lock('testLock', 1000); + expect(typeof lock.release).toBe('function'); + }); + + it('lock() - does not set lock if it already exists', async () => { + const expectedError = new ExecutionError( + 'The operation was unable to achieve a quorum during its retry window.', + [], + ); + // + await expect(lockService.lock('testLock', 1000)).rejects.toThrow(expectedError); + }); + + it('lock() - unlocks', async () => { + const lock = await lockService.lock('unlock', 1000); + const res = await lock.release(); + const attempts = await Promise.all(res.attempts); + expect(attempts.length).toBe(1); + }); + + it('lock() - expect to close connection when module is destroyed', async () => { + const spy = jest.spyOn(lockService, 'close').mockImplementation(() => Promise.resolve()); + // + await lockService.onModuleDestroy(); + expect(spy).toHaveBeenCalled(); + spy.mockRestore(); + }); +}); + +describe('Lock Service - unlocking with id', () => { + let lockService: LockService; + let lockId: string; + + beforeAll(() => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const redis = getRedisClientConfig(mockConfigService as any); + lockService = new PatchedLockService({ redis, lock: { retryCount: 0 } }); + lockService.onModuleInit(); + }); + + afterAll(async () => { + await lockService.onModuleDestroy(); + }); + + it('lock() - sets lock and gets lock id', async () => { + const { value } = await lockService.lock('customlock', 20000); + lockId = value; + expect(typeof lockId).toBe('string'); + }, 5000); + + it('get() - find existing lock', async () => { + const lock = await lockService.get('customlock', lockId); + expect(typeof lock?.value).toBe('string'); + expect(lock?.value).toBe(lockId); + }, 5000); + + it('unlock() - does not unlock with wrong id', async () => { + await expect(lockService.unlock('customlock', 'wrongid')).rejects.toThrow(); + }, 5000); + + it('unlock() - unlocks when lock id is correct', async () => { + const result = await lockService.unlock('customlock', lockId); + expect(result.attempts.length).toBe(1); + }, 5000); +}); diff --git a/packages/lock/test/patched-lock.service.mock.ts b/packages/lock/test/patched-lock.service.mock.ts new file mode 100644 index 0000000..d1fa6bb --- /dev/null +++ b/packages/lock/test/patched-lock.service.mock.ts @@ -0,0 +1,18 @@ +import IORedisMock from 'ioredis-mock'; +import Redlock from 'redlock'; + +import { LockService, LockServiceOptions } from '../src'; + +export class PatchedLockService extends LockService { + constructor(options: LockServiceOptions) { + super(options); + } + + override createConnection() { + this['redis'] = new IORedisMock(this.options.redis); + this['redlock'] = new Redlock([this['redis']], { + ...super['defaultLockOptions'], + ...(this.options.lock || {}), + }); + } +} diff --git a/packages/lock/tsconfig.json b/packages/lock/tsconfig.json new file mode 100644 index 0000000..f5b8565 --- /dev/null +++ b/packages/lock/tsconfig.json @@ -0,0 +1,22 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "module": "commonjs", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/packages/lock/tsconfig.lib.json b/packages/lock/tsconfig.lib.json new file mode 100644 index 0000000..408f0e6 --- /dev/null +++ b/packages/lock/tsconfig.lib.json @@ -0,0 +1,16 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "declaration": true, + "types": ["node"], + "target": "es2021", + "strictNullChecks": true, + "noImplicitAny": true, + "strictBindCallApply": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src/**/*.ts", "src/index.ts"], + "exclude": ["jest.config.ts", "src/**/*.mock.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] +} diff --git a/packages/lock/tsconfig.spec.json b/packages/lock/tsconfig.spec.json new file mode 100644 index 0000000..07412f0 --- /dev/null +++ b/packages/lock/tsconfig.spec.json @@ -0,0 +1,17 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "jest.config.ts", + "src/**/*.mock.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts", + "test/**/*.mock.ts", + "test/**/*.spec.ts" + ] +} diff --git a/packages/typed-event-emitter/.eslintrc.json b/packages/typed-event-emitter/.eslintrc.json new file mode 100644 index 0000000..69704e6 --- /dev/null +++ b/packages/typed-event-emitter/.eslintrc.json @@ -0,0 +1,33 @@ +{ + "extends": ["../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.json"], + "parser": "jsonc-eslint-parser", + "rules": { + "@nx/dependency-checks": [ + "error", + { + "buildTargets": ["build"], + "checkMissingDependencies": true, + "checkObsoleteDependencies": true, + "checkVersionMismatches": true + } + ] + } + } + ] +} diff --git a/packages/typed-event-emitter/CHANGELOG.md b/packages/typed-event-emitter/CHANGELOG.md new file mode 100644 index 0000000..4953b3b --- /dev/null +++ b/packages/typed-event-emitter/CHANGELOG.md @@ -0,0 +1,14 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.1.1](https://github.com/s1seven/nestjs-tools/compare/@s1seven/typed-event-emitter@0.1.0...@s1seven/typed-event-emitter@0.1.1) (2023-09-04) + +**Note:** Version bump only for package @s1seven/typed-event-emitter + +# 0.1.0 (2022-11-30) + +### Features + +- **typed-event-emitter:** create type safe event emitter ([67fa49c](https://github.com/s1seven/nestjs-tools/commit/67fa49cbe0972c0a34fbed97de65a93a7ec2f88c)) diff --git a/packages/typed-event-emitter/README.md b/packages/typed-event-emitter/README.md new file mode 100644 index 0000000..cff18de --- /dev/null +++ b/packages/typed-event-emitter/README.md @@ -0,0 +1,12 @@ +# Typed event emitter + +[![npm][npm-image]][npm-url] + +[npm-image]: https://img.shields.io/npm/v/@getlarge/typed-event-emitter.svg?style=flat +[npm-url]: https://npmjs.org/package/@getlarge/typed-event-emitter + +## Installation + +```bash +npm install --save @getlarge/typed-event-emitter +``` diff --git a/packages/typed-event-emitter/jest.config.ts b/packages/typed-event-emitter/jest.config.ts new file mode 100644 index 0000000..d6f0b47 --- /dev/null +++ b/packages/typed-event-emitter/jest.config.ts @@ -0,0 +1,12 @@ +/* eslint-disable */ +export default { + displayName: 'typed-event-emitter', + preset: '../../jest.preset.js', + testEnvironment: 'node', + transform: { + '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }], + }, + moduleFileExtensions: ['ts', 'js', 'html'], + coverageDirectory: '../../coverage/packages/typed-event-emitter', + passWithNoTests: true, +}; diff --git a/packages/typed-event-emitter/package.json b/packages/typed-event-emitter/package.json new file mode 100644 index 0000000..bba5daa --- /dev/null +++ b/packages/typed-event-emitter/package.json @@ -0,0 +1,25 @@ +{ + "name": "@getlarge/typed-event-emitter", + "version": "0.1.1", + "description": "Event emitter with generic event types", + "keywords": [ + "eventemitter", + "node", + "typescript" + ], + "license": "Apache-2.0", + "author": "Edouard Maleix ", + "homepage": "https://github.com/getlarge/nestjs-tools/tree/main/packages/typed-event-emitter", + "publishConfig": { + "registry": "https://registry.npmjs.org/" + }, + "publicConfig": { + "access": "public" + }, + "dependencies": { + "tslib": "^2.3.0" + }, + "type": "commonjs", + "main": "./src/index.js", + "typings": "./src/index.d.ts" +} diff --git a/packages/typed-event-emitter/project.json b/packages/typed-event-emitter/project.json new file mode 100644 index 0000000..7259948 --- /dev/null +++ b/packages/typed-event-emitter/project.json @@ -0,0 +1,20 @@ +{ + "name": "typed-event-emitter", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "packages/typed-event-emitter/src", + "projectType": "library", + "tags": [], + "targets": { + "build": { + "executor": "@nx/js:tsc", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/packages/typed-event-emitter", + "tsConfig": "packages/typed-event-emitter/tsconfig.lib.json", + "packageJson": "packages/typed-event-emitter/package.json", + "main": "packages/typed-event-emitter/src/index.ts", + "assets": ["packages/typed-event-emitter/*.md"] + } + } + } +} diff --git a/packages/typed-event-emitter/src/index.ts b/packages/typed-event-emitter/src/index.ts new file mode 100644 index 0000000..81412f4 --- /dev/null +++ b/packages/typed-event-emitter/src/index.ts @@ -0,0 +1 @@ +export * from './lib/typed-event-emitter'; diff --git a/packages/typed-event-emitter/src/lib/typed-event-emitter.ts b/packages/typed-event-emitter/src/lib/typed-event-emitter.ts new file mode 100644 index 0000000..7c6c525 --- /dev/null +++ b/packages/typed-event-emitter/src/lib/typed-event-emitter.ts @@ -0,0 +1,57 @@ +import { EventEmitter, on as originalOn, once as originalOnce } from 'node:events'; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type EventHandlers = Record any>; + +interface StaticEventEmitterOptions { + signal?: AbortSignal; +} + +export const once = < + Emitter extends TypedEventEmitter, + K extends Emitter extends TypedEventEmitter ? keyof X : never, +>( + emitter: Emitter, + eventName: K, + options?: StaticEventEmitterOptions, +): Promise ? X[K] : never>> => + originalOnce(emitter, eventName, options) as Promise>; + +export const on = < + Emitter extends TypedEventEmitter, + K extends Emitter extends TypedEventEmitter ? Extract : never, +>( + emitter: Emitter, + eventName: K, + options?: StaticEventEmitterOptions, +): AsyncIterableIterator ? X[K] : never>> => + originalOn(emitter, eventName, options); + +export class TypedEventEmitter extends EventEmitter { + private untypedOn = this.on; + private untypedOnce = this.once; + private untypedEmit = this.emit; + + waitOnce>( + event: K, + options?: StaticEventEmitterOptions, + ): Promise> { + return originalOnce(this, event, options) as Promise>; + } + wait>( + event: K, + options?: StaticEventEmitterOptions, + ): AsyncIterableIterator> { + return originalOn(this, event, options); + } + override on = (event: K, listener: TEvents[K]): this => this.untypedOn(event, listener); + + override once = (event: K, listener: TEvents[K]): this => this.untypedOnce(event, listener); + + override emit = (event: K, ...args: Parameters): boolean => + this.untypedEmit(event, ...args); + + constructor(options: { captureRejections?: boolean } = {}) { + super(options); + } +} diff --git a/packages/typed-event-emitter/tsconfig.json b/packages/typed-event-emitter/tsconfig.json new file mode 100644 index 0000000..f5b8565 --- /dev/null +++ b/packages/typed-event-emitter/tsconfig.json @@ -0,0 +1,22 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "module": "commonjs", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/packages/typed-event-emitter/tsconfig.lib.json b/packages/typed-event-emitter/tsconfig.lib.json new file mode 100644 index 0000000..c297a24 --- /dev/null +++ b/packages/typed-event-emitter/tsconfig.lib.json @@ -0,0 +1,16 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "declaration": true, + "types": ["node"], + "target": "es2021", + "strictNullChecks": true, + "noImplicitAny": true, + "strictBindCallApply": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src/**/*.ts"], + "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] +} diff --git a/packages/typed-event-emitter/tsconfig.spec.json b/packages/typed-event-emitter/tsconfig.spec.json new file mode 100644 index 0000000..f6d8ffc --- /dev/null +++ b/packages/typed-event-emitter/tsconfig.spec.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"] +} diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 0000000..f60dae0 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,11 @@ +sonar.organization=getlarge +sonar.projectKey=getlarge_nestjs-tools +sonar.projectName=nestjs-tools +sonar.language=ts +sonar.sourceEncoding=UTF-8 +sonar.sources=packages +sonar.test=packages +sonar.inclusions=packages/**/*.ts +sonar.test.inclusions=packages/**/test/*.spec.ts,packages/**/test/*.e2e-spec.ts +sonar.exclusions=packages/**/dist/*,packages/**/dist.browser/*,packages/**/fixtures/*,packages/**/cache/*,packages/**/node_modules/*, +sonar.javascript.lcov.reportPaths=coverage/lcov.info diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 0000000..48b880f --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,27 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "rootDir": ".", + "sourceMap": true, + "declaration": false, + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "importHelpers": true, + "target": "es2015", + "module": "esnext", + "lib": ["es2020", "dom"], + "skipLibCheck": true, + "skipDefaultLibCheck": true, + "baseUrl": ".", + "paths": { + "@getlarge/nestjs-tools-amqp-transport": ["packages/amqp-transport/src/index.ts"], + "@getlarge/nestjs-tools-async-local-storage": ["packages/async-local-storage/src/index.ts"], + "@getlarge/nestjs-tools-cluster": ["packages/cluster/src/index.ts"], + "@getlarge/nestjs-tools-file-storage": ["packages/file-storage/src/index.ts"], + "@getlarge/nestjs-tools-lock": ["packages/lock/src/index.ts"], + "@getlarge/typed-event-emitter": ["packages/typed-event-emitter/src/index.ts"] + } + }, + "exclude": ["node_modules", "tmp"] +} diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 0000000..99e8183 --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["node_modules", "test", "dist", "**/*spec.ts", "fixtures", "**/*.mock.ts"] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..cce9d0d --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "module": "commonjs", + "declaration": true, + "removeComments": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "target": "ES2021", + "sourceMap": true, + "outDir": "./dist", + "baseUrl": "./packages", + "incremental": true, + "esModuleInterop": true, + "resolveJsonModule": true + }, + "exclude": ["node_modules", "dist"] +}