diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 296b14a7..00000000 --- a/.dockerignore +++ /dev/null @@ -1,12 +0,0 @@ -.djlintrc -.env -.env.* -.eslintrc.cjs -.github -.husky -.prettierrc -CHANGELOG.md -CONTRIBUTING.md -LICENSE.md -README.md -node_modules \ No newline at end of file diff --git a/.env.example b/.env.example deleted file mode 100644 index 17010991..00000000 --- a/.env.example +++ /dev/null @@ -1,4 +0,0 @@ -USERNAME= -PASS= -DOMAIN= -PORT= diff --git a/.eslintrc.cjs b/.eslintrc.cjs index d0303475..b48fbc95 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -12,5 +12,6 @@ module.exports = { sourceType: 'module' }, rules: { - } + }, + ignorePatterns: ["**/*.jest.js", "**/prettify"], } diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml new file mode 100644 index 00000000..0ac616c7 --- /dev/null +++ b/.github/workflows/codecov.yml @@ -0,0 +1,31 @@ +name: Running Code Coverage + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [18.x, 16.x] + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + with: + fetch-depth: 2 + + - name: Set up Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + + - name: Install dependencies + run: npm install + + - name: Run tests + run: npm run test + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v1 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 8f5e43a1..8346c8fd 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -26,7 +26,7 @@ jobs: - name: Configure Node.js uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 - name: Retrieve npm cache uses: 'actions/cache@v3' @@ -37,7 +37,7 @@ jobs: ${{ runner.os }}-node- - name: Install Node packages - run: npm ci + run: npm install && npm ci - name: Get changed files id: changes run: | diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..131ba90d --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,25 @@ +name: Unit Tests + +on: [push, pull_request] + +jobs: + tests: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [18.x, 16.x] + + steps: + - uses: actions/checkout@v2 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + + - name: Install dependencies + run: npm install + + - name: Run tests + run: npm test diff --git a/.gitignore b/.gitignore index 8c959a91..8831aaf4 100644 --- a/.gitignore +++ b/.gitignore @@ -321,5 +321,4 @@ $RECYCLE.BIN/ # and uncomment the following lines # .pnp.* -# End of https://www.toptal.com/developers/gitignore/api/macos,linux,windows,webstorm,yarn,diff,snyk,node,tower - +# End of https://www.toptal.com/developers/gitignore/api/macos,linux,windows,webstorm,yarn,diff,snyk,node,tower \ No newline at end of file diff --git a/.jest/setEnvVars.js b/.jest/setEnvVars.js new file mode 100644 index 00000000..9b1e0f5c --- /dev/null +++ b/.jest/setEnvVars.js @@ -0,0 +1 @@ +process.env.DOMAIN = 'testDomain'; diff --git a/CHANGELOG.md b/CHANGELOG.md index ea75f39c..30e9316b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,60 +1,70 @@ -# How to update - -For now, the best way to upgrade is to pull the latest code from the main branch. -(One day I'll set up proper packaging with versions and stuff. That day is not today!) - -* Type `git pull origin main` -* Make sure to restart the app afterwards - -# CHANGE LOG - -## 2023-01-30 -- Fixed the missing edit button -- Fixed a bug where people without a `name` field would show up blank in some places -- Fixed a bug related to missing environment variables - -## 2023-01-29 -- Introduced a background queue system for handling outbound HTTP requests. -- Fixed follows - outbound follow requests got disabled on 01/23! Oops! -- Fixed communication with Pixelfed and GoToSocial instances. Follows and stuff should now work! - -## 2023-01-23 -- Added linting and code prettification as a pre-commit hook -- Added Github actions to run linter rules and enforce them on PRs -Huge thanks to @selfagency for these improvements! - -## 2023-01-15 -- Added a prefs page -- Added the ability to change all the emojis in the UI 👹 -- Added the ability to change what it says on the "post" button -See a video of these features in action here: https://www.loom.com/share/c8fbe3b099f644d596cd2db26e86bc8a - - -## 2023-01-14 -- All new nav! There is now a list of the 20 most recently updated feeds in the nav. Click "..." to see up to 100. -- Lots of CSS improvements! -- When you search for a user, Shuttlecraft will now also search all known users - - -## 2023-01-12 -- Prevent buttons from being double-clicked resulting in accidentally undoing something or double posting -- Prevent the account.json file from being created with a faulty domain name. Thanks @patrickmcurry! - - -## 2023-01-09 -- Fixed a bug causing new posts not to show up til the server restarts. Oops! - -## 2023-01-08 -- Added support for incoming DELETE activities. This causes matching posts to be completely removed from the system. As part of this, increased resilience for dealing with missing or unreachable posts. Thanks to @ringtailsoftware. -- Added support for editing local posts. Thanks to @ringtailsoftware. -- Renamed the sample .env to .env.example and introduced a post-install script to copy it into place -- Created this changelog! - -## 2023-01-07 -- Links in posts now automatically include noopen noreferer nofollow attributes. - -## 2023-01-06 -- Support for light/dark themes. Thanks @anildash -- Fix pagination bugs, add pagination on notifications - - +# How to update + +For now, the best way to upgrade is to pull the latest code from the main branch. +(One day I'll set up proper packaging with versions and stuff. That day is not today!) + +- Type `git pull origin main` +- Make sure to restart the app afterwards + +# CHANGE LOG + +## 2023-01-30 + +- Fixed the missing edit button +- Fixed a bug where people without a `name` field would show up blank in some places +- Fixed a bug related to missing environment variables + +## 2023-01-29 + +- Introduced a background queue system for handling outbound HTTP requests. +- Fixed follows - outbound follow requests got disabled on 01/23! Oops! +- Fixed communication with Pixelfed and GoToSocial instances. Follows and stuff should now work! + +## 2023-01-23 + +- Added linting and code prettification as a pre-commit hook +- Added Github actions to run linter rules and enforce them on PRs + Huge thanks to @selfagency for these improvements! + +## 2023-01-15 + +- Added a prefs page +- Added the ability to change all the emojis in the UI 👹 +- Added the ability to change what it says on the "post" button + See a video of these features in action here: https://www.loom.com/share/c8fbe3b099f644d596cd2db26e86bc8a + +## 2023-01-14 + +- All new nav! There is now a list of the 20 most recently updated feeds in the nav. Click "..." to see up to 100. +- Lots of CSS improvements! +- When you search for a user, Shuttlecraft will now also search all known users + +## 2023-01-12 + +- Prevent buttons from being double-clicked resulting in accidentally undoing something or double posting +- Prevent the account.json file from being created with a faulty domain name. Thanks @patrickmcurry! + +## 2023-01-09 + +- Fixed a bug causing new posts not to show up til the server restarts. Oops! + +## 2023-01-08 + +- Added support for incoming DELETE activities. This causes matching posts to be completely removed from the system. As part of this, increased resilience for dealing with missing or unreachable posts. Thanks to @ringtailsoftware. +- Added support for editing local posts. Thanks to @ringtailsoftware. +- Renamed the sample .env to .env.example and introduced a post-install script to copy it into place +- Created this changelog! + +## 2023-01-07 + +- Links in posts now automatically include noopen noreferer nofollow attributes. + +## 2023-01-06 + +- Support for light/dark themes. Thanks @anildash +- Fix pagination bugs, add pagination on notifications + +## 2023-12-08 - USERNAME Crossplatform Compatibility + +- Fixed bug of USERNAME variable not working on windows machines. +- Instead of using USERNAME we now use USER_NAME diff --git a/Caddyfile b/Caddyfile deleted file mode 100644 index 23c5f04f..00000000 --- a/Caddyfile +++ /dev/null @@ -1,3 +0,0 @@ -localhost { - reverse_proxy :3000 -} diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index fe3c22e8..00000000 --- a/Dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -FROM node:16-alpine - -# Create volume for persistent data -VOLUME /app/.data - -# Create app directory -WORKDIR /app - -# Install deps -COPY package.json ./ -COPY package-lock.json ./ -RUN npm ci --omit=dev --ignore-scripts - -# Copy source -COPY . . - -# Env Vars -ENV PORT=3000 -ENV DOMAIN="" -ENV USERNAME="" -ENV PASS="" - -# Expose port -EXPOSE $PORT - -# Start program -CMD [ "npm", "start" ] diff --git a/README.md b/README.md index e5fd7e50..0a03bb60 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,19 @@ -# SHUTTLECRAFT by Ben Brown +# SHUTTLECRAFT by the Confused Mavericks This is a project to create an "easy" way to participate in the ActivityPub "Fediverse" and other indie web protocols like RSS. -This was created and is maintained by [Ben Brown](https://benbrown.com). +This was created by [Ben Brown](https://benbrown.com) and enhanced by UCSD CSE 210 Team 6 (Confused Mavericks). Currently, this means: -- a stand-alone NodeJS web application +- a stand-alone NodeJS web application - with no external service dependencies - that is hostable on Glitch or commodity virtualhost Including features: + +- Create a fediverse account - Follow people (on Mastodon, other instances) +- Customize your fediverse profile - Compose posts and deliver on the web, and also via ActivityPub, RSS - Fave, boost and reply to posts - View notifications @@ -18,9 +21,10 @@ Including features: - Block people or instances Not yet supported: + - Media uploads -## Warning: Experimental Software! +## Warning: Experimental Software! This software should be considered an EXPERIMENTAL PROTOTYPE. Do not use it to store or exchange sensitive information. @@ -32,29 +36,22 @@ Do not use it to store or exchange sensitive information. Because of the way the Mastodon works, once you start to engage with users on other instances, you will start to receive traffic from a -wide array of other instances -- not all of which is necessary or +wide array of other instances -- not all of which is necessary or relevant to you. As a result, operating this software on a small basis may result in unexpected amounts of incoming traffic. ## Warning: Known limitations! -My goal with this app is to not use any major external services. +Our goal with this app is to not use any major external services. As a result, all data is written as PLAIN TEXT FILES to the disk. Right now, the app builds an IN-MEMORY INDEX of EVERY SINGLE POST. This will work for several thousand posts, but ... maybe not for 10,000s of posts. -I'm not sure how far it will go. I have ideas about being able to -shard the index into multiple files and page through it, etc. But. ALSO, there is nothing fancy happening in terms of queuing or rate limiting outgoing posts. When you post, it will send out HTTP requests right away, all at once. This may cause issues. -## Acknowledgements - -This project owes a great debt to @dariusk's excellent [express-activitypub](https://github.com/dariusk/express-activitypub) repo. -My work started from his reference implementation, and there are many lines of code cribbed from his work. - ## Bug Reports & Contributions Please file bugs on Github: @@ -64,26 +61,19 @@ Please read the [contributor's guide](CONTRIBUTING.md) before sending pull reque ## Install -Quick start: [Remix on Glitch](#easiest-glitch) - -Clone the repo: -`git clone git@github.com:benbrown/shuttlecraft.git` +Quick start: [Remix on Glitch](https://glitch.com/edit/#!/import/github/CSE-210-Team-6/shuttlecraft) -Enter folder: -`cd shuttlecraft` +- Remix the repo on glitch: +`https://github.com/CSE-210-Team-6/shuttlecraft.git` -Install node dependencies: -`npm install` +- Go to settings -> Edit project details -> Change the project name to what you want. This will be your website domain You are ready to run! But first, set your configuration. -When you are ready to start, run: -`npm start` - ## Config Initial configuration of your instance is done by editing the -.env file to include your desired USERNAME, PASSWORD, and DOMAIN NAME. +.env file to include your desired DOMAIN NAME. These values MUST BE SET before you launch the application, as they are used to generate your account details, including your Fediverse actor ID. @@ -91,37 +81,27 @@ Fediverse actor ID. In the .env file, put: ``` -USERNAME=yourusername -PASS=yourpasswordforadmintools -DOMAIN=yourdomainname -PORT=3000 +DOMAIN={your-project-name}.glitch.me +PORT={not required but can specify} ``` -USERNAME and PASS are required to login to the private dashboard tools. - When you launch the app for the first time, these values will be used to create the `.data/account.json` file which is the source of your public account information, and will be used for many operations. -There is currently no UI built to view or manage your account. If you -need to make updates, edit the JSON directly. - HOWEVER PLEASE NOTE that your ID is a real URL, and it must reflect the real URL served by this app. Also note that it is embedded in every post you write - so if you change values in the `account.json` file, your previous posts may break. +## Access -## Login - -To login, visit `https://yourdomain.com/private` and provide the username and password from your .env file - - +Access your website at `https://{yourdomain}.com/private`. You will be prompted to create account or login if required. ## Debugging If you want more logging or want to see what is happening in the background, -enable debugging by adding DEBUG=ono:* to the .env file, or starting the app +enable debugging by adding DEBUG=ono:\* to the .env file, or starting the app with: `DEBUG=ono:* npm start` @@ -139,10 +119,9 @@ Cached user information is in `.data/users` Follower list, following list, like list, boost list, block list, and notifications can all be found in their own files at the root -of the `.data` folder. This is your data! Back it up if you care +of the `.data` folder. This is your data! Back it up if you care about it. - ## Host This is a node app that runs by default on port 3000, or the port @@ -151,31 +130,20 @@ specified in the .env file. In order to play nice with the fediverse, it must be hosted on an SSL-enabled endpoint. -### Easiest: Glitch +### Easy: Glitch Use Glitch to create a new project! Glitch will provide you with hosting for your instance of Shuttlecraft, and you can start for FREE! -It all starts when you click this link -> [Remix this project on Glitch](https://glitch.com/edit/#!/import/github/benbrown/shuttlecraft) <-- +It all starts when you click this link -> [Remix this project on Glitch](https://glitch.com/edit/#!/import/github/CSE-210-Team-6/shuttlecraft) <-- WHOA! What happened? Well, a copy of the Shuttlecraft code was sent to a new, unique, owned-by-you web server and it started getting set up. You just need to make it yours by following these steps: 1. First, make sure the URL of your Glitch project is the one you like. You can change it in the "Settings" menu. -2. Then, configure the options [as described above](#config) using the .env editor. -3. Finally, login to the dashboard at `https://yourdomain.glitch.me/private`. -4. Done! - -### Basic: Reverse proxy - -1. Clone the repo to your own server. -2. Configure it and set it up to run on a port of your choosing. -3. Configure Caddy or Nginx with a Certbot SSL certificate. -4. Configure your domain to proxy requests to the localhost port. - -A sample `Caddyfile` is included in the repo. [Install Caddy](https://caddyserver.com/download) and run: -``` -caddy run --config Caddyfile -``` +2. Then, configure the options [as described above](#config) using the .env editor. +3. Finally, create and login to the dashboard at `https://yourdomain.glitch.me/private`. +4. It is very important that the domain you add while creating you user is `https://{yourdomain}.glitch.me`. If not this will break things! +5. Done! ### Advanced: Docker @@ -186,33 +154,37 @@ caddy run --config Caddyfile ``` 3. Test locally: ``` - docker run -e PORT=3000 -e DOMAIN="your-domain.com" -e USERNAME="yourUsername" -e PASS="yourPassword" -p "3000:3000" "${yourRegistryUsername}/shuttlecraft" + docker run -e PORT=3000 -e DOMAIN="your-domain.com" -p "3000:3000" "${yourRegistryUsername}/shuttlecraft" ``` 4. Push the image to your registry: ``` docker push "${yourRegistryUsername}/shuttlecraft:latest" ``` -5. Deploy the image to your container platform with the required environment variables (`DOMAIN`, `USERNAME`, `PASS`). -6. Configure a web service to proxy requests to the container port and provide HTTPS (see "Reverse proxy" above). +5. Deploy the image to your container platform with the required environment variables (`DOMAIN`). +6. Configure a web service to proxy requests to the container port and provide HTTPS (see "Reverse proxy" above). ## Customize This app uses HandlebarsJS for templating. Customize the public pages: + - Templates are in `design/public/home.handlebars` and `design/public/note.handlebars` and `design/layouts/public.handlebars` - CSS is in `public/css/main.css` Customize your avatar: + - Replace `public/images/avatar.png` - As necessary, update the url in `.data/account.json` inside the actor.icon.url field Customize the backend: + - Templates are in `design/dashboard.handlebars` and `design/notifications.handlebars` and `design/layouts/private.handlebars` - Some common components in `design/partials` - CSS in `public/css/secret.css` To block users or instances: + - Add an entry to the file at `.data/blocks` - You can block a user using their actor ID (something like https://foo.bar/@jerk) or their entire domain (https://foo.bar/) -- Restart the app +- Restart the app diff --git a/babel.config.cjs b/babel.config.cjs new file mode 100644 index 00000000..a1db3ce9 --- /dev/null +++ b/babel.config.cjs @@ -0,0 +1,3 @@ +module.exports = { + presets: [['@babel/preset-env', {targets: {node: 'current'}}]], +}; \ No newline at end of file diff --git a/design/createAccount.handlebars b/design/createAccount.handlebars new file mode 100644 index 00000000..585cae8a --- /dev/null +++ b/design/createAccount.handlebars @@ -0,0 +1,32 @@ +
+

Create User Account

+ + + + + + + + + +
\ No newline at end of file diff --git a/design/dashboard.handlebars b/design/dashboard.handlebars index a9f394c7..49386570 100644 --- a/design/dashboard.handlebars +++ b/design/dashboard.handlebars @@ -20,24 +20,31 @@ {{else}}

Follow some people to fill your feed with posts.

-

I suggest following me! - I'm benbrown@hackers.town +

We suggest following our Professor Thomas Powell! You can find him at + thomasapowell@fosstodon.org

{{/if}} -{{#if next}} -More -{{/if}} + {{#if next}} + + {{/if}} + diff --git a/design/dms.handlebars b/design/dms.handlebars index 7dff60d2..ff5b4c62 100644 --- a/design/dms.handlebars +++ b/design/dms.handlebars @@ -15,7 +15,6 @@ {{> minicomposer inReplyTo=lastIncoming to=feed.id}} {{else}} -
Select a conversation. To create a new one, navigate to a profile.
@@ -23,5 +22,7 @@ {{/if}} \ No newline at end of file + document.addEventListener('DOMContentLoaded', () => { + app.pollForPosts(); + }); + diff --git a/design/feeds.handlebars b/design/feeds.handlebars index 7c486885..3d429b77 100644 --- a/design/feeds.handlebars +++ b/design/feeds.handlebars @@ -23,7 +23,6 @@ {{/with}} {{/each}} {{else}} -
No posts. Reload
diff --git a/design/findresults.handlebars b/design/findresults.handlebars index 8335e628..47d24770 100644 --- a/design/findresults.handlebars +++ b/design/findresults.handlebars @@ -18,6 +18,9 @@ {{/if}} + \ No newline at end of file + document.addEventListener('DOMContentLoaded', () => { + app.pollForPosts(); + }); + diff --git a/design/followers.handlebars b/design/followers.handlebars index 7f5a8643..ab8baa54 100644 --- a/design/followers.handlebars +++ b/design/followers.handlebars @@ -10,6 +10,9 @@ {{/each}} {{> peopleTools}} + \ No newline at end of file + document.addEventListener('DOMContentLoaded', () => { + app.pollForPosts(); + }); + diff --git a/design/following.handlebars b/design/following.handlebars index 8e568b8c..2d33a8b2 100644 --- a/design/following.handlebars +++ b/design/following.handlebars @@ -10,6 +10,9 @@ {{/each}} {{> peopleTools}} + \ No newline at end of file + document.addEventListener('DOMContentLoaded', () => { + app.pollForPosts(); + }); + diff --git a/design/layouts/authentication.handlebars b/design/layouts/authentication.handlebars new file mode 100644 index 00000000..7be415c7 --- /dev/null +++ b/design/layouts/authentication.handlebars @@ -0,0 +1,17 @@ + + + + {{me.preferredUsername}} + + + + + + + + + {{{body}}} + + + + \ No newline at end of file diff --git a/design/layouts/public.handlebars b/design/layouts/public.handlebars index 14f6f301..615e13c8 100644 --- a/design/layouts/public.handlebars +++ b/design/layouts/public.handlebars @@ -1,19 +1,22 @@ - - {{me.preferredUsername}} - - - - - - -
-
-
- {{{body}}} -
-
-
- - + + + {{me.preferredUsername}} + + + + + + + +
+
+
+ {{{body}}} +
+
+
+ + + \ No newline at end of file diff --git a/design/login.handlebars b/design/login.handlebars new file mode 100644 index 00000000..4cdee14b --- /dev/null +++ b/design/login.handlebars @@ -0,0 +1,14 @@ +
+

Login

+ + + + + {{#if message}} +
{{message}}
+ {{/if}} + + +
\ No newline at end of file diff --git a/design/notifications.handlebars b/design/notifications.handlebars index 27c75067..27f92f54 100644 --- a/design/notifications.handlebars +++ b/design/notifications.handlebars @@ -4,7 +4,7 @@ {{#each notifications}} -
+
{{#with this}} {{#isEq notification.type "Announce"}} @@ -38,13 +38,16 @@ {{/if}}
+ \ No newline at end of file + document.addEventListener('DOMContentLoaded', () => { + {{#isEq offset "0"}} + {{#each ../notifications}} + {{#if @first}} + app.latestNotification("{{this.time}}"); + {{/if}} + {{/each}} + {{/isEq}} + app.pollForPosts(); + }); + diff --git a/design/partials/avatar.handlebars b/design/partials/avatar.handlebars index 32e69c9e..f9969bf9 100644 --- a/design/partials/avatar.handlebars +++ b/design/partials/avatar.handlebars @@ -1,7 +1,21 @@ {{#unless nolink}}{{/unless}} - {{#if actor.icon.url}} + {{#if actor.icon.url }} {{else}} - + {{/if}} -{{#unless nolink}}{{/unless}} \ No newline at end of file +{{#unless nolink}}{{/unless}} + +{{!-- + + --}} \ No newline at end of file diff --git a/design/partials/composer.handlebars b/design/partials/composer.handlebars index 41d9e7f9..239522ba 100644 --- a/design/partials/composer.handlebars +++ b/design/partials/composer.handlebars @@ -2,7 +2,6 @@ {{#if originalPost}}
Reply
- {{> byline actor=actor}} {{{originalPost.content}}}
{{else}} @@ -15,17 +14,15 @@
- - + - {{/if}} +
+ + + + + + +
diff --git a/design/partials/minicomposer.handlebars b/design/partials/minicomposer.handlebars index 13b83293..f76fec0e 100644 --- a/design/partials/minicomposer.handlebars +++ b/design/partials/minicomposer.handlebars @@ -1,11 +1,14 @@ -
-
-
- - - - - -
-
+
+
+
+ + + + + + + + +
+
\ No newline at end of file diff --git a/design/partials/note.handlebars b/design/partials/note.handlebars index e270b5ff..b86c5b4e 100644 --- a/design/partials/note.handlebars +++ b/design/partials/note.handlebars @@ -1,48 +1,56 @@ - {{#unless hidebyline}} - {{> byline actor=actor}} - {{/unless}} - {{#if note.summary}} -
- ⚠️ {{note.summary}} -
- Toggle -
+
+ {{#unless hidebyline}} + {{> byline actor=actor}} + {{/unless}} + {{#if note.summary}} +
+ ⚠️ {{note.summary}} +
+ Toggle
- {{/if}} -
- {{{note.content}}} +
+ {{/if}} +
+ {{{note.content}}} - {{#if note.inReplyTo}} -

Show Thread

- {{/if}} + {{#if note.inReplyTo}} +

Show Thread

+ {{/if}} - {{#each note.attachment}} -
- {{#isImage mediaType}} - {{../name}} - {{/isImage}} - {{#isVideo mediaType}} - - {{/isVideo}} -
- {{/each}} -
-
- - - - {{#isEq note.attributedTo @root.me.id}} - - {{/isEq}} -
- -
-
+ {{#each note.attachment}} +
+ {{#isImage mediaType}} + {{../name}} + {{/isImage}} + {{#isVideo mediaType}} + + {{/isVideo}} +
+ {{/each}} +
+
+ {{#if note.canReply}} + + {{/if}} + {{#if note.canBoost}} + + {{/if}} + {{#if note.canFave}} + + {{/if}} + {{#isEq note.attributedTo @root.me.id}} + + {{/isEq}} +
+ +
+
+
diff --git a/design/prefs.handlebars b/design/prefs.handlebars index c8c634cd..21e228a1 100644 --- a/design/prefs.handlebars +++ b/design/prefs.handlebars @@ -1,86 +1,122 @@ + {{> peopleTools}} -
-
Outbound Queue
-
+
+
Outbound Queue
+
{{#isEq queue.state 0}}✅{{/isEq}} {{#isEq queue.state 1}}🟢{{/isEq}} {{#isEq queue.state 3}}🔴{{/isEq}} {{#if queue.size}} + {{#if queue.shouldRun}}Running.{{/if}} {{queue.size}} items remain. + {{else}} - Queue empty + Queue empty {{/if}}
-
-
-
Preferences
-
+ + +
+
Preferences
+
- - Interface Strings - - -

- - -

+ Interface Strings +
+ + +
- - Emoji Buttons - - -

- - -

-

- - -

-

- - -

-

- - -

-

- - -

-

- - -

-

- - -

-

- - -

-

- - -

-

- - -

-

- - -

-

- - -

+ Emoji Buttons + {{#each prefs.icons as |icon key|}} +
+ {{!-- --}} + + +
+ {{/each}} + +
+ + +
+
+ Account Profile +
+ + +
+
+ + +
+
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
+
+ + + -
+
-
\ No newline at end of file +
+ + \ No newline at end of file diff --git a/design/public/home.handlebars b/design/public/home.handlebars index 15488080..2f8b87a6 100644 --- a/design/public/home.handlebars +++ b/design/public/home.handlebars @@ -1,27 +1,31 @@ -
- -
+ +
{{#if actor.image}} {{/if}} -
-
+ +
-
-
+ +
{{actor.name}} {{getUsername actor.id}} - + + {{#if actor.bio}} +

{{actor.bio}}

+ {{/if}} + {{{actor.summary}}} {{#if actor.attachment}} @@ -37,7 +41,7 @@ {{/if}}
-
+
🏠 Latest @@ -87,4 +91,4 @@
{{/each}} More -
+ \ No newline at end of file diff --git a/docs/ActivityPub.js.html b/docs/ActivityPub.js.html new file mode 100644 index 00000000..7d32b45e --- /dev/null +++ b/docs/ActivityPub.js.html @@ -0,0 +1,605 @@ + + + + + JSDoc: Source: ActivityPub.js + + + + + + + + + + +
+ +

Source: ActivityPub.js

+ + + + + + +
+
+
import fetch from 'node-fetch';
+import crypto from 'crypto';
+import debug from 'debug';
+import { queue } from './queue.js';
+const logger = debug('ActivityPub');
+
+/**
+ * ActivityPubClient - a class for sending and fetching ActivityPub content
+ * @class
+ */
+export class ActivityPubClient {
+  /**
+   * Constructor for ActivityPubClient
+   * @constructor
+   * @param {Object} account - The user account.
+   */
+  constructor(account) {
+    logger('Initializing ActivityPub client for user:', account);
+    if (account) {
+      this.account = account;
+    }
+  }
+
+  /**
+   * Setter for actor property
+   * @param {Object} actor - The actor object.
+   */
+  set actor(actor) {
+    this._actor = actor;
+  }
+
+  /**
+   * Getter for actor property
+   * @returns {Object} The actor object.
+   */
+  get actor() {
+    return this._actor;
+  }
+
+  /**
+   * Setter for account property
+   * @param {Object} account - The user account.
+   */
+  set account(account) {
+    logger('Setting account:', account);
+    this._account = account;
+    this._actor = account?.actor;
+  }
+
+  /**
+   * Getter for account property
+   * @returns {Object} The user account.
+   */
+  get account() {
+    return this._account;
+  }
+
+  /**
+   * Fetches the Webfinger data for a given username
+   * @async
+   * @param {string} username - The username to fetch Webfinger data for.
+   * @returns {Promise<Object>} The Webfinger data.
+   * @throws {Error} If Webfinger fetch fails.
+   */
+  async webfinger(username) {
+    const { targetDomain } = this.getUsernameDomain(username);
+
+    const webfingerUrl = `https://${targetDomain}/.well-known/webfinger?resource=acct:${username}`;
+
+    logger(`fetch webfinger ${webfingerUrl}`);
+    const finger = await fetch(webfingerUrl, {
+      headers: {
+        Accept: 'application/jrd+json, application/json, application/ld+json'
+      }
+    });
+    if (finger.ok) {
+      const webfinger = await finger.json();
+      return webfinger;
+    } else {
+      throw new Error(`could not get webfinger ${webfingerUrl}: ${finger.status}`);
+    }
+  }
+
+  /**
+   * Fetches the actor data for a given user ID
+   * @async
+   * @param {string} userId - The user ID to fetch actor data for.
+   * @returns {Promise<Object>} The actor data.
+   * @throws {Error} If actor fetch fails.
+   */
+  async fetchActor(userId) {
+    const actorQuery = await ActivityPub.fetch(userId, {});
+    if (actorQuery.ok) {
+      const actor = await actorQuery.json();
+      return actor;
+    } else {
+      throw new Error('failed to load actor');
+    }
+  }
+
+  /**
+   * Fetch an ActivityPub URL using the current actor to sign the request
+   * @param {*} targetUrl url of activitypub resource
+   * @param {*} options options for the fetch, excluding header
+   * @returns a fetch promise
+   */
+  async fetch(targetUrl, options) {
+    logger('Fetch:', targetUrl);
+
+    const url = new URL(targetUrl);
+    const urlFragment = url.pathname + (url.searchParams.toString() ? `?${url.searchParams.toString()}` : '');
+
+    const signer = crypto.createSign('sha256');
+    const date = new Date();
+    const stringToSign = `(request-target): get ${urlFragment}\nhost: ${url.hostname}\ndate: ${date.toUTCString()}`;
+    signer.update(stringToSign);
+    signer.end();
+    const signature = signer.sign(this.account.privateKey);
+    const signatureB64 = signature.toString('base64');
+    const header = `keyId="${this.actor.publicKey.id}",headers="(request-target) host date",signature="${signatureB64}"`;
+    options.headers = {
+      Date: date.toUTCString(),
+      Host: url.hostname,
+      Accept: 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
+      Signature: header
+    };
+
+    const controller = new AbortController();
+    // set timeout for 5s
+    setTimeout(() => controller.abort(), 5000);
+    options.signal = controller.signal;
+
+    const query = fetch(targetUrl, options);
+
+    return query;
+  }
+
+  /**
+   * Send an ActivityPub activity to a user
+   * @param {*} recipient
+   * @param {*} message
+   * @returns a fetch result
+   */
+  async send(recipient, message) {
+    queue.enqueue(() => {
+      let url;
+      try {
+        url = new URL(recipient.inbox);
+      } catch (err) {
+        console.error('INVALID INBOX URL', recipient);
+        throw err;
+      }
+      const inboxFragment = url.pathname;
+
+      const digestHash = crypto.createHash('sha256').update(JSON.stringify(message)).digest('base64');
+      const signer = crypto.createSign('sha256');
+      const date = new Date();
+      const stringToSign = `(request-target): post ${inboxFragment}\nhost: ${
+        url.hostname
+      }\ndate: ${date.toUTCString()}\ndigest: SHA-256=${digestHash}`;
+      signer.update(stringToSign);
+      signer.end();
+      const signature = signer.sign(this.account.privateKey);
+      const signatureB64 = signature.toString('base64');
+      const header = `keyId="${this.actor.publicKey.id}",headers="(request-target) host date digest",signature="${signatureB64}"`;
+
+      logger('OUTBOUND TO ', recipient.inbox);
+      logger('MESSAGE', message);
+
+      const controller = new AbortController();
+      setTimeout(() => controller.abort(), 10000);
+      return fetch(
+        recipient.inbox,
+        {
+          headers: {
+            Host: url.hostname,
+            'Content-type': 'application/activity+json',
+            Date: date.toUTCString(),
+            Digest: `SHA-256=${digestHash}`,
+            Signature: header
+          },
+          method: 'POST',
+          json: true,
+          body: JSON.stringify(message),
+          signal: controller.signal
+        },
+        function (error, response) {
+          if (error) {
+            console.error('Error sending outbound message:', error, response);
+          } else {
+            logger('Response', response.status);
+          }
+        }
+      );
+    });
+  }
+
+  /**
+   * Send a like message to the author of a post
+   * @param {*} post activity being liked
+   * @param {*} recipient actor record for author of post
+   * @returns
+   */
+  async sendLike(post, recipient) {
+    const guid = crypto.randomBytes(16).toString('hex');
+    const message = {
+      '@context': 'https://www.w3.org/ns/activitystreams',
+      id: `${this.actor.id}/likes/${guid}`,
+      type: 'Like',
+      actor: this.actor.id,
+      object: post.id
+    };
+
+    ActivityPub.send(recipient, message);
+
+    // return the guid to make this undoable.
+    return message;
+  }
+
+  /**
+   * Send an undo message about a like that was sent previously.
+   * @param {*} post post that is being unliked
+   * @param {*} recipient  actor record for author of post
+   * @param {*} originalActivityId id of original outbound like activity that is being undone
+   * @returns
+   */
+  async sendUndoLike(post, recipient, originalActivityId) {
+    const message = {
+      '@context': 'https://www.w3.org/ns/activitystreams',
+      id: `${originalActivityId}/undo`,
+      type: 'Undo',
+      actor: this.actor.id,
+      object: {
+        id: `${originalActivityId}`,
+        type: 'Like',
+        actor: this.actor.id,
+        object: post.id
+      }
+    };
+    ActivityPub.send(recipient, message);
+    return message;
+  }
+
+  /**
+   * Send a follow request
+   * @param {*} recipient
+   * @returns
+   */
+  async sendFollow(recipient) {
+    const guid = crypto.randomBytes(16).toString('hex');
+    const message = {
+      '@context': 'https://www.w3.org/ns/activitystreams',
+      id: `${this.actor.id}/follows/${guid}`,
+      type: 'Follow',
+      actor: this.actor.id,
+      object: recipient.id
+    };
+    ActivityPub.send(recipient, message);
+
+    // return the guid to make this undoable.
+    return message;
+  }
+
+  /**
+   * Send an undo about a previously sent follow
+   * @param {*} recipient
+   * @param {*} originalActivityId
+   * @returns
+   */
+  async sendUndoFollow(recipient, originalActivityId) {
+    const message = {
+      '@context': 'https://www.w3.org/ns/activitystreams',
+      id: `${originalActivityId}/undo`,
+      type: 'Undo',
+      actor: this.actor.id,
+      object: {
+        id: originalActivityId,
+        type: 'Follow',
+        actor: this.actor.id,
+        object: recipient.id
+      }
+    };
+    ActivityPub.send(recipient, message);
+
+    // return the guid to make this undoable.
+    return message;
+  }
+
+  /**
+   * Send an Accept for an incoming follow request
+   * @param {*} followRequest
+   */
+  async sendAccept(recipient, followRequest) {
+    const guid = crypto.randomBytes(16).toString('hex');
+    const message = {
+      '@context': 'https://www.w3.org/ns/activitystreams',
+      id: `${this.actor.id}/accept/${guid}`,
+      type: 'Accept',
+      actor: this.actor.id,
+      object: followRequest
+    };
+    ActivityPub.send(recipient, message);
+
+    return message;
+  }
+
+  /**
+   * Send an outbound update activity to a follower or recipient of a message
+   * @param {*} recipient
+   * @param {*} object
+   * @returns
+   */
+  async sendUpdate(recipient, object) {
+    const message = {
+      '@context': 'https://www.w3.org/ns/activitystreams',
+      id: `${object.id}/activity`,
+      published: object.published,
+      type: 'Update',
+      actor: this.actor.id,
+      object,
+      to: object.to,
+      cc: object.cc
+    };
+    ActivityPub.send(recipient, message);
+    return message;
+  }
+
+  /**
+   * Send an outbound create activity to a follower or recipient of a message
+   * @param {*} recipient
+   * @param {*} object
+   * @returns
+   */
+  async sendCreate(recipient, object) {
+    const message = {
+      '@context': 'https://www.w3.org/ns/activitystreams',
+      id: `${object.id}/activity`,
+      published: object.published,
+      type: 'Create',
+      actor: this.actor.id,
+      object,
+      to: object.to,
+      cc: object.cc
+    };
+    ActivityPub.send(recipient, message);
+    return message;
+  }
+
+  /**
+   * Send a boost for a specific post to the posts author and our followers
+   * @param {*} primaryRecipient
+   * @param {*} post
+   * @param {*} followers
+   * @returns
+   */
+  async sendBoost(primaryRecipient, post, followers) {
+    const guid = crypto.randomBytes(16).toString('hex');
+
+    // send to followers and original poster
+    const recipients = [
+      this.actor.followers, // this is a reference to the follower list that we will dereference later
+      primaryRecipient.id // this is a reference to the recipient
+    ];
+
+    const message = {
+      '@context': 'https://www.w3.org/ns/activitystreams',
+      id: `${this.actor.id}/boosts/${guid}`,
+      type: 'Announce',
+      actor: this.actor.id,
+      published: new Date().toISOString(),
+      object: post.id,
+      to: ['https://www.w3.org/ns/activitystreams#Public'],
+      cc: recipients
+    };
+
+    // deliver outbound messages to all recipients
+    recipients.forEach(recipient => {
+      // if the recipient is "my followers", send it to them
+      if (recipient === this.actor.followers) {
+        followers.forEach(follower => {
+          ActivityPub.send(follower, message);
+        });
+      } else {
+        // otherwise, send it directly to the person
+        ActivityPub.send(primaryRecipient, message);
+      }
+    });
+
+    // return the guid to make this undoable.
+    return message;
+  }
+
+  /**
+   * Send an undo of a previously sent boost
+   * @param {*} primaryRecipient
+   * @param {*} post
+   * @param {*} followers
+   * @param {*} originalActivityId
+   * @returns
+   */
+  async sendUndoBoost(primaryRecipient, post, followers, originalActivityId) {
+    // send to followers and original poster
+    const recipients = [
+      this.actor.followers, // this is a reference to the follower list that we will dereference later
+      post.attributedTo // this is a reference to the recipient
+    ];
+
+    const message = {
+      '@context': 'https://www.w3.org/ns/activitystreams',
+      id: `${originalActivityId}/undo`,
+      type: 'Undo',
+      actor: this.actor.id,
+      object: {
+        id: originalActivityId,
+        type: 'Announce',
+        actor: this.actor.id,
+        object: post.id
+      },
+      to: ['https://www.w3.org/ns/activitystreams#Public'],
+      cc: recipients
+    };
+
+    // deliver outbound messages to all recipients
+    recipients.forEach(recipient => {
+      // if the recipient is "my followers", send it to them
+      if (recipient === this.actor.followers) {
+        followers.forEach(follower => {
+          ActivityPub.send(follower, message);
+        });
+      } else {
+        // otherwise, send it directly to the person
+        ActivityPub.send(primaryRecipient, message);
+      }
+    });
+
+    // return the guid to make this undoable.
+    return message;
+  }
+
+  getUsernameDomain(userIdorName) {
+    let targetDomain = '';
+    let username = '';
+    if (!userIdorName) {
+      return { username, targetDomain };
+    }
+    if (userIdorName.startsWith('https://')) {
+      const actor = new URL(userIdorName);
+      targetDomain = actor.hostname;
+      username = actor.pathname.split(/\//);
+      username = username[username.length - 1];
+    } else {
+      // handle leading @
+      [username, targetDomain] = userIdorName.replace(/^@/, '').split('@');
+    }
+
+    return {
+      username,
+      targetDomain
+    };
+  }
+
+  getUsername(userIdorName) {
+    const { username, targetDomain } = this.getUsernameDomain(userIdorName);
+    return `${username}@${targetDomain}`;
+  }
+
+  async fetchOutbox(actor) {
+    if (actor.outbox) {
+      try {
+        const actorQuery = await ActivityPub.fetch(actor.outbox, {});
+        if (actorQuery.ok) {
+          const rootOutbox = await actorQuery.json();
+          let items = [];
+          let outboxPage;
+          // find the first element.
+          if (rootOutbox.first) {
+            if (typeof rootOutbox.first === 'string') {
+              const pageQuery = await ActivityPub.fetch(rootOutbox.first, {});
+              if (pageQuery.ok) {
+                outboxPage = await pageQuery.json();
+                items = outboxPage.orderedItems || [];
+              } else {
+                logger(
+                  'failed to load outbox first page',
+                  rootOutbox.first,
+                  pageQuery.status,
+                  pageQuery.statusText,
+                  await pageQuery.text()
+                );
+              }
+            } else {
+              items = rootOutbox.first.orderedItems || [];
+              outboxPage = rootOutbox.first;
+            }
+          }
+
+          return {
+            outbox: rootOutbox,
+            page: outboxPage,
+            items
+          };
+        } else {
+          logger(
+            'failed to load outbox index',
+            actor.outbox,
+            actorQuery.status,
+            actorQuery.statusText,
+            await actorQuery.text()
+          );
+        }
+      } catch (err) {
+        console.error(err);
+      }
+    }
+    return [];
+  }
+
+  /**
+   * Validate the signature on an incoming request to the inbox
+   * @param {*} actor
+   * @param {*} req
+   * @returns true if signature is valid
+   */
+  validateSignature(actor, req) {
+    const signature = {};
+    req.headers.signature
+      .split(/,/)
+      .map(c => c.split(/=/))
+      .forEach(([key, val]) => {
+        signature[key] = val.replace(/^"/, '').replace(/"$/, '');
+        return signature[key];
+      });
+    // construct string from headers
+    const fields = signature.headers.split(/\s/);
+    const str = fields
+      .map(f => (f === '(request-target)' ? '(request-target): post /api/inbox' : `${f}: ${req.header(f)}`))
+      .join('\n');
+    try {
+      if (actor) {
+        const verifier = crypto.createVerify('RSA-SHA256');
+        verifier.update(str);
+        const res = verifier.verify(actor.publicKey.publicKeyPem, signature.signature, 'base64');
+        return res;
+      } else {
+        return false;
+      }
+    } catch (err) {
+      // console.error(err); // any server will get a lot of junk Deletes
+      return false;
+    }
+  }
+}
+
+export const ActivityPub = new ActivityPubClient();
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.2 on Thu Dec 14 2023 18:11:22 GMT-0800 (Pacific Standard Time) +
+ + + + + diff --git a/docs/ActivityPubClient.html b/docs/ActivityPubClient.html new file mode 100644 index 00000000..0d647750 --- /dev/null +++ b/docs/ActivityPubClient.html @@ -0,0 +1,2906 @@ + + + + + JSDoc: Class: ActivityPubClient + + + + + + + + + + +
+ +

Class: ActivityPubClient

+ + + + + + +
+ +
+ +

ActivityPubClient(account)

+ +
ActivityPubClient - a class for sending and fetching ActivityPub content
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new ActivityPubClient(account)

+ + + + + + +
+ Constructor for ActivityPubClient +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
account + + +Object + + + + The user account.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +

Classes

+ +
+
ActivityPubClient
+
+
+ + + + + + + + + +

Members

+ + + +

account

+ + + + +
+ Setter for account property +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

account

+ + + + +
+ Getter for account property +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

actor

+ + + + +
+ Setter for actor property +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

actor

+ + + + +
+ Getter for actor property +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

(async) fetch(targetUrl, options)

+ + + + + + +
+ Fetch an ActivityPub URL using the current actor to sign the request +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
targetUrl + + +* + + + + url of activitypub resource
options + + +* + + + + options for the fetch, excluding header
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ a fetch promise +
+ + + + + + + + + + + + + + + +

(async) fetchActor(userId) → {Promise.<Object>}

+ + + + + + +
+ Fetches the actor data for a given user ID +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userId + + +string + + + + The user ID to fetch actor data for.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
Throws:
+ + + +
+
+
+ If actor fetch fails. +
+
+
+
+
+
+ Type +
+
+ +Error + + +
+
+
+
+
+ + + + + +
Returns:
+ + +
+ The actor data. +
+ + + +
+
+ Type +
+
+ +Promise.<Object> + + +
+
+ + + + + + + + + + + + + +

(async) send(recipient, message)

+ + + + + + +
+ Send an ActivityPub activity to a user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
recipient + + +* + + + +
message + + +* + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ a fetch result +
+ + + + + + + + + + + + + + + +

(async) sendAccept(followRequest)

+ + + + + + +
+ Send an Accept for an incoming follow request +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
followRequest + + +* + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendBoost(primaryRecipient, post, followers)

+ + + + + + +
+ Send a boost for a specific post to the posts author and our followers +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
primaryRecipient + + +* + + + +
post + + +* + + + +
followers + + +* + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + +

(async) sendCreate(recipient, object)

+ + + + + + +
+ Send an outbound create activity to a follower or recipient of a message +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
recipient + + +* + + + +
object + + +* + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + +

(async) sendFollow(recipient)

+ + + + + + +
+ Send a follow request +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
recipient + + +* + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + +

(async) sendLike(post, recipient)

+ + + + + + +
+ Send a like message to the author of a post +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
post + + +* + + + + activity being liked
recipient + + +* + + + + actor record for author of post
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + +

(async) sendUndoBoost(primaryRecipient, post, followers, originalActivityId)

+ + + + + + +
+ Send an undo of a previously sent boost +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
primaryRecipient + + +* + + + +
post + + +* + + + +
followers + + +* + + + +
originalActivityId + + +* + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + +

(async) sendUndoFollow(recipient, originalActivityId)

+ + + + + + +
+ Send an undo about a previously sent follow +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
recipient + + +* + + + +
originalActivityId + + +* + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + +

(async) sendUndoLike(post, recipient, originalActivityId)

+ + + + + + +
+ Send an undo message about a like that was sent previously. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
post + + +* + + + + post that is being unliked
recipient + + +* + + + + actor record for author of post
originalActivityId + + +* + + + + id of original outbound like activity that is being undone
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + +

(async) sendUpdate(recipient, object)

+ + + + + + +
+ Send an outbound update activity to a follower or recipient of a message +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
recipient + + +* + + + +
object + + +* + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + +

validateSignature(actor, req)

+ + + + + + +
+ Validate the signature on an incoming request to the inbox +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
actor + + +* + + + +
req + + +* + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ true if signature is valid +
+ + + + + + + + + + + + + + + +

(async) webfinger(username) → {Promise.<Object>}

+ + + + + + +
+ Fetches the Webfinger data for a given username +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
username + + +string + + + + The username to fetch Webfinger data for.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
Throws:
+ + + +
+
+
+ If Webfinger fetch fails. +
+
+
+
+
+
+ Type +
+
+ +Error + + +
+
+
+
+
+ + + + + +
Returns:
+ + +
+ The Webfinger data. +
+ + + +
+
+ Type +
+
+ +Promise.<Object> + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.2 on Thu Dec 14 2023 18:11:22 GMT-0800 (Pacific Standard Time) +
+ + + + + \ No newline at end of file diff --git a/docs/Markdown.js.html b/docs/Markdown.js.html new file mode 100644 index 00000000..9b169da9 --- /dev/null +++ b/docs/Markdown.js.html @@ -0,0 +1,105 @@ + + + + + JSDoc: Source: Markdown.js + + + + + + + + + + +
+ +

Source: Markdown.js

+ + + + + + +
+
+
/* This module contains the markdown renderer used to format posts
+
+ By default, urls will be linkifies with nofollow, noopener, and noreferrer attributes
+ Override those attributes by setting LINK_ATTRIBUTES in the .env file
+
+Usage:
+const html = md.render(markdown);
+
+*/
+
+import dotenv from 'dotenv';
+import MarkdownIt from 'markdown-it';
+
+dotenv.config();
+
+const md = new MarkdownIt({
+  html: true,
+  linkify: true
+});
+
+const LINK_ATTRIBUTES = process.env.LINK_ATTRIBUTES || 'nofollow noopener noreferrer';
+
+/**
+ * The above function modifies the rendering of link tags in Markdown by adding a "rel" attribute with
+ * the value of LINK_ATTRIBUTES.
+ * @param tokens - The `tokens` parameter is an array of token objects. Each token object represents a
+ * part of the Markdown document, such as a paragraph, heading, link, etc. The `tokens` array is passed
+ * to the renderer function to generate the corresponding HTML output.
+ * @param idx - The `idx` parameter in the code refers to the index of the current token being rendered
+ * in the array of tokens.
+ * @param options - The `options` parameter is an object that contains various options and
+ * configurations for the Markdown renderer. It can include settings such as the rendering mode, the
+ * HTML tag names to use for different elements, and other customization options.
+ * @param env - The `env` parameter in the code snippet refers to the environment object. It is an
+ * optional parameter that can be used to pass additional information or configuration to the rendering
+ * rules. It can be used to store and access data that needs to be shared between different rendering
+ * rules.
+ * @param self - The `self` parameter refers to the Markdown-it instance. It is used to access the
+ * `renderToken` method and the `renderer` object, which contains the rules for rendering Markdown
+ * tokens.
+ *
+ * customize the link formatter to include noopener noreferrer links
+ * this prevents browsers from telling downstream pages about where the links came from
+ * and protects the privacy of our users.
+ * code from: https://publishing-project.rivendellweb.net/customizing-markdown-it/
+ */
+const proxy = (tokens, idx, options, env, self) => self.renderToken(tokens, idx, options);
+const defaultLinkOpenRenderer = md.renderer.rules.link_open || proxy;
+md.renderer.rules.link_open = function (tokens, idx, options, env, self) {
+  tokens[idx].attrJoin('rel', LINK_ATTRIBUTES);
+  return defaultLinkOpenRenderer(tokens, idx, options, env, self);
+};
+
+export { md, LINK_ATTRIBUTES };
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.2 on Thu Dec 14 2023 18:11:22 GMT-0800 (Pacific Standard Time) +
+ + + + + diff --git a/docs/account.js.html b/docs/account.js.html new file mode 100644 index 00000000..eb1796a1 --- /dev/null +++ b/docs/account.js.html @@ -0,0 +1,178 @@ + + + + + JSDoc: Source: account.js + + + + + + + + + + +
+ +

Source: account.js

+ + + + + + +
+
+
import express from 'express';
+import { getFollowers } from '../lib/account.js';
+
+/**
+ * Express.js router for handling user profile-related routes.
+ *
+ * @typedef {Object} UserProfileRouter
+ * @property {Function} getProfile - Route handler for retrieving a user profile by name.
+ * @property {Function} getFollowers - Route handler for retrieving followers of a user profile by name.
+ *
+ * @example
+ * // Example usage:
+ * const userProfileRouter = express.Router();
+ * userProfileRouter.get('/:name', userProfileHandlers.getProfile);
+ * userProfileRouter.get('/:name/followers', userProfileHandlers.getFollowers);
+ * app.use('/profiles', userProfileRouter);
+ */
+export const router = express.Router();
+
+/**
+ * Handle GET requests for a user profile by name.
+ *
+ * @function
+ * @param {Object} req - Express.js request object.
+ * @param {Object} res - Express.js response object.
+ * @returns {void} Responds with a user profile or redirects based on the request.
+ *
+ * @throws {Error} Responds with a 400 Bad Request if the 'name' parameter is missing.
+ * @throws {Error} Responds with a 404 Not Found if no record is found for the provided 'name'.
+ *
+ * @example
+ * // Example route:
+ * // GET /profiles/:name
+ * router.get('/:name', function (req, res) {
+ *   // ... (route handler implementation)
+ * });
+ */
+router.get('/:name', (req, res) => {
+  // Extract the 'name' parameter from the request
+  let name = req.params.name;
+
+  // Handle missing 'name' parameter with a 400 Bad Request response
+  if (!name) {
+    return res.status(400).send('Bad request.');
+  } else {
+    // Obtain the domain from the app settings
+    const domain = req.app.get('domain');
+
+    // Append the user profile URL path to the domain
+    name = `https://${domain}/u/${name}`;
+
+    // Check if the provided 'name' matches the stored user profile ID
+    if (name !== req.app.get('account').actor.id) {
+      // Respond with a 404 Not Found if no record is found for the provided 'name'
+      return res.status(404).send(`No record found for ${name}.`);
+    } else {
+      // Check the 'Accept' header for JSON-LD format and respond accordingly
+      if (req.headers.accept?.includes('application/ld+json')) {
+        // Respond with the user profile in JSON-LD format
+        res.json(req.app.get('account').actor);
+      } else {
+        // Redirect to the user profile URL or the default domain
+        res.redirect(req.app.get('account').actor.url || `https://${domain}/`);
+      }
+    }
+  }
+});
+
+/**
+ * Handle GET requests for the followers of a user profile by name.
+ *
+ * @function
+ * @param {Object} req - Express.js request object.
+ * @param {Object} res - Express.js response object.
+ * @returns {void} Responds with a collection of followers or an error message based on the request.
+ *
+ * @throws {Error} Responds with a 400 Bad Request if the 'name' parameter is missing.
+ * @throws {Error} Responds with a 404 Not Found if no record is found for the provided 'name'.
+ *
+ * @example
+ * // Example route:
+ * // GET /profiles/:name/followers
+ * router.get('/:name/followers', function (req, res) {
+ *   // ... (route handler implementation)
+ * });
+ */
+router.get('/:name/followers', (req, res) => {
+  // Extract the 'name' parameter from the request
+  let name = req.params.name;
+
+  // Handle missing 'name' parameter with a 400 Bad Request response
+  if (!name) {
+    return res.status(400).send('Bad request.');
+  } else {
+    // Obtain the domain from the app settings
+    const domain = req.app.get('domain');
+
+    // Append the user profile URL path to the domain
+    name = `https://${domain}/u/${name}`;
+
+    // Check if the provided 'name' matches the stored user profile ID
+    if (name !== req.app.get('account').actor.id) {
+      // Respond with a 404 Not Found if no record is found for the provided 'name'
+      return res.status(404).send(`No record found for ${name}.`);
+    } else {
+      // Retrieve followers for the user profile
+      const followers = getFollowers();
+
+      // Assemble the followers collection in ActivityStreams format
+      const followersCollection = {
+        type: 'OrderedCollection',
+        totalItems: followers.length,
+        id: `https://${domain}/u/${name}/followers`,
+        first: {
+          type: 'OrderedCollectionPage',
+          totalItems: followers.length,
+          partOf: `https://${domain}/u/${name}/followers`,
+          orderedItems: followers,
+          id: `https://${domain}/u/${name}/followers?page=1`
+        },
+        '@context': ['https://www.w3.org/ns/activitystreams']
+      };
+      // Respond with the followers collection in JSON format
+      res.json(followersCollection);
+    }
+  }
+});
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.2 on Thu Dec 14 2023 18:13:17 GMT-0800 (Pacific Standard Time) +
+ + + + + diff --git a/docs/authentication.js.html b/docs/authentication.js.html new file mode 100644 index 00000000..c67cc37b --- /dev/null +++ b/docs/authentication.js.html @@ -0,0 +1,181 @@ + + + + + JSDoc: Source: authentication.js + + + + + + + + + + +
+ +

Source: authentication.js

+ + + + + + +
+
+
import dotenv from 'dotenv';
+import { ensureAccount, getAccount } from './account.js';
+import { promises as fsPromises } from 'fs';
+import { ActivityPub } from './ActivityPub.js';
+
+/**
+ * The function `getUsername` retrieves the value of the `USER_NAME` environment variable.
+ * @returns The function `getUsername` is returning the value of the `USER_NAME` environment variable.
+ */
+const getUsername = () => {
+  dotenv.config();
+  const { USER_NAME } = process.env;
+  return USER_NAME;
+};
+
+/**
+ * The function `getPassword` retrieves the value of the `PASS` environment variable using the `dotenv`
+ * package.
+ * @returns The function `getPassword` is returning the value of the `PASS` environment variable.
+ */
+const getPassword = () => {
+  dotenv.config();
+  const { PASS } = process.env;
+  return PASS;
+};
+
+/**
+ * The function `authenticateLogin` checks if the provided username and password match the stored
+ * username and password.
+ * @param username - The `username` parameter is the username entered by the user during the login
+ * process.
+ * @param password - The `password` parameter is the password entered by the user during the login
+ * process.
+ * @returns a boolean value. It returns true if the provided username and password match the stored
+ * username and password, and false otherwise.
+ */
+export const authenticateLogin = (username, password) => {
+  if (username === getUsername() && password === getPassword()) {
+    return true;
+  }
+  return false;
+};
+
+/**
+ * The `createAccount` function creates a new account, sets the account in the app, sets a token in a
+ * cookie, and redirects to a private route.
+ * @param req - The `req` parameter is an object that represents the HTTP request made by the client.
+ * It contains information such as the request headers, request body, request method, request URL, and
+ * other relevant details.
+ * @param res - The `res` parameter is the response object that is used to send the response back to
+ * the client. It contains methods and properties that allow you to control the response, such as
+ * setting headers, sending data, and redirecting the client to a different URL.
+ */
+export const createAccount = async (req, res) => {
+  const { username, domain } = req.body;
+
+  try {
+    await ensureAccount(username, domain);
+
+    // Set account in the app
+    const myaccount = await getAccount();
+    req.app.set('account', myaccount);
+
+    // Set token in cookie
+    res.cookie('token', myaccount.apikey);
+
+    // Redirect to private route
+    res.redirect('/private');
+  } catch (error) {
+    console.error('Error creating account:', error);
+    res.status(500).send('Internal Server Error');
+  }
+};
+
+/**
+ * The function `writeEnvToFile` writes the values of `username`, `password`, and `domain` to a `.env`
+ * file.
+ * @param req - The `req` parameter is an object that represents the HTTP request made to the server.
+ * It contains information about the request, such as the request method, headers, and body.
+ * @param res - The `res` parameter is the response object. It is used to send a response back to the
+ * client after the operation is completed.
+ */
+export const writeEnvToFile = async (req, res) => {
+  const { username, password, domain } = req.body;
+
+  const envData = `
+    USER_NAME=${username}
+    PASS=${password}
+    DOMAIN=${domain}
+    `;
+
+  const envFilePath = './.env';
+
+  try {
+    await fsPromises.writeFile(envFilePath, envData);
+    console.log('Data has been written to .env file');
+  } catch (error) {
+    console.error('Error writing to .env file:', error);
+  }
+};
+
+/**
+ * The function checks if the user is authenticated by comparing the token in the request cookies with
+ * the API key stored in the account, and redirects to the login page if not authenticated.
+ * @param req - The `req` parameter is the request object, which contains information about the
+ * incoming HTTP request from the client. It includes properties such as the request headers, query
+ * parameters, request body, cookies, etc.
+ * @param res - The `res` parameter is the response object that is used to send a response back to the
+ * client. It contains methods and properties that allow you to control the response, such as setting
+ * headers, sending data, and redirecting the client to a different URL.
+ * @param next - The `next` parameter is a function that is used to pass control to the next middleware
+ * function in the request-response cycle. It is typically called at the end of the current middleware
+ * function to indicate that it has completed its processing and the next middleware function should be
+ * called.
+ * @returns If the condition `req.cookies.token && req.cookies.token === myaccount.apikey` is true,
+ * then the `next()` function will be called, which means the control will be passed to the next
+ * middleware function in the request-response cycle.
+ */
+export const handleAuthenticatedUser = (req, res, next) => {
+  const myaccount = getAccount();
+  req.app.set('account', myaccount);
+  ActivityPub.account = myaccount;
+
+  if (req.cookies.token && req.cookies.token === myaccount.apikey) {
+    console.log('TOKEN', req.cookies);
+    return next();
+  } else {
+    res.redirect('/account/login');
+  }
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.2 on Thu Dec 14 2023 18:11:22 GMT-0800 (Pacific Standard Time) +
+ + + + + diff --git a/docs/fonts/OpenSans-Bold-webfont.eot b/docs/fonts/OpenSans-Bold-webfont.eot new file mode 100644 index 00000000..5d20d916 Binary files /dev/null and b/docs/fonts/OpenSans-Bold-webfont.eot differ diff --git a/docs/fonts/OpenSans-Bold-webfont.svg b/docs/fonts/OpenSans-Bold-webfont.svg new file mode 100644 index 00000000..3ed7be4b --- /dev/null +++ b/docs/fonts/OpenSans-Bold-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/fonts/OpenSans-Bold-webfont.woff b/docs/fonts/OpenSans-Bold-webfont.woff new file mode 100644 index 00000000..1205787b Binary files /dev/null and b/docs/fonts/OpenSans-Bold-webfont.woff differ diff --git a/docs/fonts/OpenSans-BoldItalic-webfont.eot b/docs/fonts/OpenSans-BoldItalic-webfont.eot new file mode 100644 index 00000000..1f639a15 Binary files /dev/null and b/docs/fonts/OpenSans-BoldItalic-webfont.eot differ diff --git a/docs/fonts/OpenSans-BoldItalic-webfont.svg b/docs/fonts/OpenSans-BoldItalic-webfont.svg new file mode 100644 index 00000000..6a2607b9 --- /dev/null +++ b/docs/fonts/OpenSans-BoldItalic-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/fonts/OpenSans-BoldItalic-webfont.woff b/docs/fonts/OpenSans-BoldItalic-webfont.woff new file mode 100644 index 00000000..ed760c06 Binary files /dev/null and b/docs/fonts/OpenSans-BoldItalic-webfont.woff differ diff --git a/docs/fonts/OpenSans-Italic-webfont.eot b/docs/fonts/OpenSans-Italic-webfont.eot new file mode 100644 index 00000000..0c8a0ae0 Binary files /dev/null and b/docs/fonts/OpenSans-Italic-webfont.eot differ diff --git a/docs/fonts/OpenSans-Italic-webfont.svg b/docs/fonts/OpenSans-Italic-webfont.svg new file mode 100644 index 00000000..e1075dcc --- /dev/null +++ b/docs/fonts/OpenSans-Italic-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/fonts/OpenSans-Italic-webfont.woff b/docs/fonts/OpenSans-Italic-webfont.woff new file mode 100644 index 00000000..ff652e64 Binary files /dev/null and b/docs/fonts/OpenSans-Italic-webfont.woff differ diff --git a/docs/fonts/OpenSans-Light-webfont.eot b/docs/fonts/OpenSans-Light-webfont.eot new file mode 100644 index 00000000..14868406 Binary files /dev/null and b/docs/fonts/OpenSans-Light-webfont.eot differ diff --git a/docs/fonts/OpenSans-Light-webfont.svg b/docs/fonts/OpenSans-Light-webfont.svg new file mode 100644 index 00000000..11a472ca --- /dev/null +++ b/docs/fonts/OpenSans-Light-webfont.svg @@ -0,0 +1,1831 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/fonts/OpenSans-Light-webfont.woff b/docs/fonts/OpenSans-Light-webfont.woff new file mode 100644 index 00000000..e7860748 Binary files /dev/null and b/docs/fonts/OpenSans-Light-webfont.woff differ diff --git a/docs/fonts/OpenSans-LightItalic-webfont.eot b/docs/fonts/OpenSans-LightItalic-webfont.eot new file mode 100644 index 00000000..8f445929 Binary files /dev/null and b/docs/fonts/OpenSans-LightItalic-webfont.eot differ diff --git a/docs/fonts/OpenSans-LightItalic-webfont.svg b/docs/fonts/OpenSans-LightItalic-webfont.svg new file mode 100644 index 00000000..431d7e35 --- /dev/null +++ b/docs/fonts/OpenSans-LightItalic-webfont.svg @@ -0,0 +1,1835 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/fonts/OpenSans-LightItalic-webfont.woff b/docs/fonts/OpenSans-LightItalic-webfont.woff new file mode 100644 index 00000000..43e8b9e6 Binary files /dev/null and b/docs/fonts/OpenSans-LightItalic-webfont.woff differ diff --git a/docs/fonts/OpenSans-Regular-webfont.eot b/docs/fonts/OpenSans-Regular-webfont.eot new file mode 100644 index 00000000..6bbc3cf5 Binary files /dev/null and b/docs/fonts/OpenSans-Regular-webfont.eot differ diff --git a/docs/fonts/OpenSans-Regular-webfont.svg b/docs/fonts/OpenSans-Regular-webfont.svg new file mode 100644 index 00000000..25a39523 --- /dev/null +++ b/docs/fonts/OpenSans-Regular-webfont.svg @@ -0,0 +1,1831 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/fonts/OpenSans-Regular-webfont.woff b/docs/fonts/OpenSans-Regular-webfont.woff new file mode 100644 index 00000000..e231183d Binary files /dev/null and b/docs/fonts/OpenSans-Regular-webfont.woff differ diff --git a/docs/global.html b/docs/global.html new file mode 100644 index 00000000..4b029e45 --- /dev/null +++ b/docs/global.html @@ -0,0 +1,771 @@ + + + + + JSDoc: Global + + + + + + + + + + +
+ +

Global

+ + + + + + +
+ +
+ +

+ + +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(async) unrollThread()

+ + + + + + +
+ publish the post to go up the stream +check all the posts below and above the threads +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Type Definitions

+ + + +

ActivityPubRouter

+ + + + +
+ Express.js router for handling incoming ActivityPub requests. +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
processActivity + + +function + + + + Route handler for processing incoming ActivityPub requests.
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + +
Example
+ +
// Example usage:
+import { router as activityPubRouter } from './activityPubRouter';
+app.use('/activitypub', activityPubRouter);
+ + + + + +

OutboxRouter

+ + + + +
+ Express.js router for handling requests related to the user's outbox. +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
getOutbox + + +function + + + + Route handler for retrieving the user's outbox posts.
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + +
Example
+ +
// Example usage:
+import { router as outboxRouter } from './outboxRouter';
+app.use('/outbox', outboxRouter);
+ + + + + +

UserProfileRouter

+ + + + +
+ Express.js router for handling user profile-related routes. +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
getProfile + + +function + + + + Route handler for retrieving a user profile by name.
getFollowers + + +function + + + + Route handler for retrieving followers of a user profile by name.
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + +
Example
+ +
// Example usage:
+const userProfileRouter = express.Router();
+userProfileRouter.get('/:name', userProfileHandlers.getProfile);
+userProfileRouter.get('/:name/followers', userProfileHandlers.getFollowers);
+app.use('/profiles', userProfileRouter);
+ + + + + +

WebfingerRouter

+ + + + +
+ Express.js router for handling webfinger-related routes. +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
getResource + + +function + + + + Route handler for retrieving a webfinger resource.
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + +
Example
+ +
// Example usage:
+import { router as webfingerRouter } from './webfingerRouter';
+app.use('/webfinger', webfingerRouter);
+ + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.2 on Thu Dec 14 2023 18:13:17 GMT-0800 (Pacific Standard Time) +
+ + + + + \ No newline at end of file diff --git a/docs/inbox.js.html b/docs/inbox.js.html new file mode 100644 index 00000000..de15f96e --- /dev/null +++ b/docs/inbox.js.html @@ -0,0 +1,263 @@ + + + + + JSDoc: Source: inbox.js + + + + + + + + + + +
+ +

Source: inbox.js

+ + + + + + +
+
+
import express from 'express';
+import { ActivityPub } from '../lib/ActivityPub.js';
+import { fetchUser } from '../lib/users.js';
+import {
+  acceptDM,
+  addFollower,
+  removeFollower,
+  follow,
+  isReplyToMyPost,
+  addNotification,
+  isMyPost,
+  isBlocked,
+  addressedOnlyToMe,
+  isMention,
+  deleteObject
+} from '../lib/account.js';
+import { createActivity, recordLike, recordUndoLike, recordBoost, getActivity } from '../lib/notes.js';
+import debug from 'debug';
+import { isIndexed } from '../lib/storage.js';
+const logger = debug('ono:inbox');
+
+/**
+ * Express.js router for handling incoming ActivityPub requests.
+ *
+ * @typedef {Object} ActivityPubRouter
+ * @property {Function} processActivity - Route handler for processing incoming ActivityPub requests.
+ *
+ * @example
+ * // Example usage:
+ * import { router as activityPubRouter } from './activityPubRouter';
+ * app.use('/activitypub', activityPubRouter);
+ */
+export const router = express.Router();
+
+/**
+ * Route handler for processing incoming ActivityPub requests.
+ *
+ * @function
+ * @async
+ * @param {Object} req - Express.js request object.
+ * @param {Object} res - Express.js response object.
+ * @returns {Promise<void>} Resolves with a success response or rejects with an error response.
+ *
+ * @throws {Error} Responds with a 403 Forbidden if the actor is blocked.
+ * @throws {Error} Responds with a 403 Forbidden if the signature validation fails.
+ *
+ * @example
+ * // Example route:
+ * // POST /activitypub
+ * activityPubRouter.post('/', activityPubHandlers.processActivity);
+ */
+router.post('/', async (req, res) => {
+  /**
+   * The incoming ActivityPub request payload.
+   *
+   * @type {Object}
+   * @property {string} type - The type of the incoming request (e.g., 'Create', 'Follow', 'Like').
+   * @property {Object} actor - The actor associated with the request.
+   * @property {Object} object - The object of the request, containing the main content.
+   */
+  const incomingRequest = req.body;
+
+  if (incomingRequest) {
+    if (isBlocked(incomingRequest.actor)) {
+      return res.status(403).send('');
+    }
+
+    logger('New message', JSON.stringify(incomingRequest, null, 2));
+    logger('Looking up actor', incomingRequest.actor);
+
+    /**
+     * The user object obtained from fetching the actor of the incoming request.
+     *
+     * @type {Object}
+     * @property {Object} actor - The actor object representing the user.
+     */
+    const { actor } = await fetchUser(incomingRequest.actor);
+
+    // FIRST, validate the actor
+    if (ActivityPub.validateSignature(actor, req)) {
+      switch (incomingRequest.type) {
+        case 'Delete':
+          logger('Delete request');
+          await deleteObject(actor, incomingRequest);
+          break;
+        case 'Follow':
+          logger('Incoming follow request');
+          addFollower(incomingRequest);
+
+          // TODO: should wait to confirm follow acceptance?
+          ActivityPub.sendAccept(actor, incomingRequest);
+          break;
+        case 'Undo':
+          logger('Incoming undo');
+          switch (incomingRequest.object.type) {
+            case 'Follow':
+              logger('Incoming unfollow request');
+              removeFollower(incomingRequest.actor);
+              break;
+            case 'Like':
+              logger('Incoming undo like request');
+              recordUndoLike(incomingRequest.object);
+              break;
+            default:
+              logger('Unknown undo type');
+          }
+          break;
+        case 'Accept':
+          switch (incomingRequest.object.type) {
+            case 'Follow':
+              logger('Incoming follow request');
+              follow(incomingRequest);
+              break;
+            default:
+              logger('Unknown undo type');
+          }
+          break;
+        case 'Like':
+          logger('Incoming like');
+          recordLike(incomingRequest);
+          break;
+        case 'Announce':
+          logger('Incoming boost');
+          // determine if this is a boost on MY post
+          // or someone boosting a post into my feed. DIFFERENT!
+          if (
+            isMyPost({
+              id: incomingRequest.object
+            })
+          ) {
+            recordBoost(incomingRequest);
+          } else {
+            // fetch the boosted post if it doesn't exist
+            try {
+              await getActivity(incomingRequest.object);
+            } catch (err) {
+              console.error('Could not fetch boosted post');
+            }
+
+            // log the boost itself to the activity stream
+            try {
+              createActivity(incomingRequest);
+            } catch (err) {
+              console.error('Could not fetch boosted post...');
+            }
+          }
+          break;
+        case 'Create':
+          logger('incoming create');
+
+          // determine what type of post this is, if it should show up, etc.
+          // - a post that is a reply to your own post from someone you follow (notification AND feed)
+          // - a post that is a reply to your own post from someone you do not follow (notification only)
+          // - a post that that is from someone you follow, and is a reply to a post from someone you follow (in feed)
+          // - a post that is from someone you follow, but is a reply to a post from someone you do not follow (should be ignored?)
+          // - a mention from a following (notification and feed)
+          // - a mention from a stranger (notification only)
+          if (incomingRequest.object.directMessage === true || addressedOnlyToMe(incomingRequest)) {
+            await acceptDM(incomingRequest.object, incomingRequest.object.attributedTo);
+          } else if (isReplyToMyPost(incomingRequest.object)) {
+            // TODO: What about replies to replies? should we traverse up a bit?
+            if (!isIndexed(incomingRequest.object.id)) {
+              createActivity(incomingRequest.object);
+              addNotification({
+                type: 'Reply',
+                actor: incomingRequest.object.attributedTo,
+                object: incomingRequest.object.id
+              });
+            } else {
+              logger('already created reply');
+            }
+          } else if (isMention(incomingRequest.object)) {
+            if (!isIndexed(incomingRequest.object.id)) {
+              createActivity(incomingRequest.object);
+              addNotification({
+                type: 'Mention',
+                actor: incomingRequest.object.attributedTo,
+                object: incomingRequest.object.id
+              });
+            } else {
+              logger('already created mention');
+            }
+          } else if (!incomingRequest.object.inReplyTo) {
+            // this is a NEW post - most likely from a follower
+            createActivity(incomingRequest.object);
+          } else {
+            // this is a reply
+            // from a following
+            // or from someone else who replied to a following?
+            // the visibility should be determined on the feed
+            // TODO: we may want to discard things NOT from followings
+            // since they may never be seen
+            // and we can always go fetch them...
+            createActivity(incomingRequest.object);
+          }
+
+          break;
+        case 'Update':
+          createActivity(incomingRequest.object);
+          break;
+        default:
+          logger('Unknown request type:', incomingRequest.type);
+      }
+    } else {
+      logger('Signature failed:', incomingRequest);
+      return res.status(403).send('Invalid signature');
+    }
+  } else {
+    logger('Unknown request format:', incomingRequest);
+  }
+  return res.status(200).send();
+});
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.2 on Thu Dec 14 2023 18:13:17 GMT-0800 (Pacific Standard Time) +
+ + + + + diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 00000000..6f1a88bf --- /dev/null +++ b/docs/index.html @@ -0,0 +1,65 @@ + + + + + JSDoc: Home + + + + + + + + + + +
+ +

Home

+ + + + + + + + +

+ + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.2 on Thu Dec 14 2023 18:13:17 GMT-0800 (Pacific Standard Time) +
+ + + + + \ No newline at end of file diff --git a/docs/notes.js.html b/docs/notes.js.html new file mode 100644 index 00000000..41013b4e --- /dev/null +++ b/docs/notes.js.html @@ -0,0 +1,247 @@ + + + + + JSDoc: Source: notes.js + + + + + + + + + + +
+ +

Source: notes.js

+ + + + + + +
+
+
import fs from 'fs';
+import debug from 'debug';
+import { addNotification, isBlocked, writeNotifications, getNotifications } from './account.js';
+import {
+  INDEX,
+  readJSONDictionary,
+  writeJSONDictionary,
+  fromIndex,
+  deleteActivityFromIndex,
+  deleteJSONDictionary,
+  addActivityToIndex,
+  addFailureToIndex,
+  createFileName,
+  getFileName,
+  getLikesFileName
+} from './storage.js';
+import { ActivityPub } from './ActivityPub.js';
+
+const logger = debug('ono:notes');
+
+/**
+ * The function `getLikesForNote` retrieves the likes and boosts for a given note ID from a JSON
+ * dictionary.
+ * @returns The function `getLikesForNote` is returning the result of calling the `readJSONDictionary`
+ * function with the `fileName` and an object containing `likes` and `boosts` properties.
+ */
+export const getLikesForNote = id => {
+  const fileName = getLikesFileName(id);
+  return readJSONDictionary(fileName, {
+    likes: [],
+    boosts: []
+  });
+};
+
+/**
+ * The function `getReplyCountForNote` returns the number of replies for a given note ID.
+ * @returns The number of replies for a given note ID.
+ */
+export const getReplyCountForNote = id => {
+  return INDEX.filter(i => i.inReplyTo === id).length;
+};
+
+/**
+ * The function records a like for a note and adds the actor to the list of likes if they haven't
+ * already liked the note.
+ */
+export const recordLike = request => {
+  const actor = request.actor;
+  const noteId = request.object;
+
+  logger('INCOMING LIKE FOR', noteId);
+
+  const likes = getLikesForNote(noteId);
+  if (likes.likes.indexOf(actor) < 0) {
+    likes.likes.push(actor);
+    const fileName = getLikesFileName(noteId);
+    writeJSONDictionary(fileName, likes);
+    addNotification(request);
+  }
+};
+
+/**
+ * The function `recordBoost` records a boost for a note and adds the actor to the list of boosts if
+ * they haven't already boosted the note.
+ */
+export const recordBoost = request => {
+  const actor = request.actor;
+  const noteId = request.object;
+
+  logger('INCOMING BOOST FOR', noteId);
+
+  const likes = getLikesForNote(noteId);
+  if (likes.boosts.indexOf(actor) < 0) {
+    likes.boosts.push(actor);
+    const fileName = getLikesFileName(noteId);
+    writeJSONDictionary(fileName, likes);
+    addNotification(request);
+  }
+};
+
+/**
+ * The function `recordUndoLike` removes the actor's like from the likes list for a given note and
+ * updates the likes file.
+ */
+export const recordUndoLike = request => {
+  const actor = request.actor;
+  const noteId = request.object;
+
+  logger('INCOMING UNLIKE FOR', noteId);
+
+  const likes = getLikesForNote(noteId);
+  likes.likes = likes.likes.filter(a => a !== actor);
+  const fileName = getLikesFileName(noteId);
+  writeJSONDictionary(fileName, likes);
+};
+
+/**
+ * The `deleteActivity` function deletes an activity and its associated notifications from the system.
+ * @param id - The `id` parameter represents the unique identifier of the activity that needs to be
+ * deleted. It is used to locate the corresponding note file and delete it.
+ * @param tombstone - The `tombstone` parameter is not used in the code snippet provided. It is
+ * mentioned in a comment, but there is no code that utilizes it.
+ */
+export const deleteActivity = (id, tombstone) => {
+  const noteFile = getFileName(id);
+  if (fs.existsSync(noteFile)) {
+    // rather than capture a tombstone, just delete it like it never was.
+    deleteActivityFromIndex(id);
+    deleteJSONDictionary(noteFile);
+
+    // delete any reply or mention notifications
+    const notifications = getNotifications();
+    writeNotifications(
+      notifications.filter(n => {
+        // filter only notifications that are replies or mentions
+        if ((n.notification.type === 'Reply' || n.notification.type === 'Mention') && n.notification.object === id) {
+          return false;
+        }
+        return true;
+      })
+    );
+  }
+};
+
+/**
+ * The `createActivity` function creates a new activity by writing a note to a file and adding it to an
+ * index if the file does not already exist.
+ */
+export const createActivity = note => {
+  const noteFile = createFileName(note);
+  if (!fs.existsSync(noteFile)) {
+    addActivityToIndex(note);
+  }
+  writeJSONDictionary(noteFile, note);
+};
+
+/**
+ * The function `getActivity` retrieves activity data either from a cache or by fetching it from a
+ * remote source, handling potential errors along the way.
+ * @returns The function `getActivity` returns a Promise that resolves to the result of either
+ * `readJSONDictionary(noteFile, {})` or `fetchActivity(id)`.
+ */
+export const getActivity = async id => {
+  try {
+    if (isBlocked(id)) {
+      throw new Error('Content is from blocked domain', id);
+    }
+    const indexed = fromIndex(id);
+    if (indexed !== false) {
+      // if is cached, no need to check for file
+      if (indexed.type === 'fail') {
+        // TODO: could retry after a while...
+        throw new Error('Activity was unreachable', indexed);
+      } else {
+        const noteFile = getFileName(id);
+        return readJSONDictionary(noteFile, {});
+      }
+    } else {
+      return await fetchActivity(id);
+    }
+  } catch (err) {
+    console.error('Failed to getActivity', err);
+    throw err;
+  }
+};
+
+/**
+ * The function fetches an activity using its ID and handles any errors that occur during the process.
+ * @returns The `fetchActivity` function returns the `activity` object if the fetch is successful.
+ */
+const fetchActivity = async activityId => {
+  logger('FETCH ', activityId);
+  try {
+    const query = await ActivityPub.fetch(activityId, {});
+    if (query.ok) {
+      const activity = await query.json();
+      createActivity(activity);
+      return activity;
+    } else {
+      console.error('Failed to fetch', activityId, 'REASON:', query.statusText);
+      addFailureToIndex({
+        id: activityId,
+        time: new Date().getTime(),
+        status: query.status
+      });
+      throw new Error('could not get post', activityId);
+    }
+  } catch (err) {
+    addFailureToIndex({
+      id: activityId,
+      time: new Date().getTime(),
+      status: err.message
+    });
+    throw new Error('could not get post', activityId);
+  }
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.2 on Thu Dec 14 2023 18:11:22 GMT-0800 (Pacific Standard Time) +
+ + + + + diff --git a/docs/outbox.js.html b/docs/outbox.js.html new file mode 100644 index 00000000..02491567 --- /dev/null +++ b/docs/outbox.js.html @@ -0,0 +1,164 @@ + + + + + JSDoc: Source: outbox.js + + + + + + + + + + +
+ +

Source: outbox.js

+ + + + + + +
+
+
import express from 'express';
+import dotenv from 'dotenv';
+
+import { getOutboxPosts } from '../lib/account.js';
+
+dotenv.config();
+
+/**
+ * Express.js router for handling requests related to the user's outbox.
+ *
+ * @typedef {Object} OutboxRouter
+ * @property {Function} getOutbox - Route handler for retrieving the user's outbox posts.
+ *
+ * @example
+ * // Example usage:
+ * import { router as outboxRouter } from './outboxRouter';
+ * app.use('/outbox', outboxRouter);
+ */
+export const router = express.Router();
+
+// const {
+//     DOMAIN
+// } = process.env;
+
+/**
+ * Route handler for retrieving the user's outbox posts.
+ *
+ * @function
+ * @async
+ * @param {Object} req - Express.js request object.
+ * @param {Object} res - Express.js response object.
+ * @returns {Promise<void>} Resolves with the user's outbox collection or rejects with an error response.
+ *
+ * @throws {Error} Responds with a 400 Bad Request if the 'offset' query parameter is not a valid number.
+ *
+ * @example
+ * // Example route:
+ * // GET /outbox
+ * outboxRouter.get('/', outboxHandlers.getOutbox);
+ */
+router.get('/', async (req, res) => {
+  /**
+   * The result object containing the total number of posts and an array of outbox posts.
+   *
+   * @type {Object}
+   * @property {number} total - The total number of outbox posts.
+   * @property {Array<Object>} posts - An array of outbox posts.
+   */
+  const { total, posts } = await getOutboxPosts(req.query.offset || 0);
+
+  /**
+   * The URL of the user's outbox.
+   *
+   * @type {string}
+   */
+  const outboxUrl = req.app.get('account').actor.outbox;
+
+  /**
+   * The representation of the outbox collection to be sent in the response.
+   *
+   * @type {Object}
+   * @property {string} type - The type of the collection ('OrderedCollection' or 'OrderedCollectionPage').
+   * @property {number} totalItems - The total number of items in the collection.
+   * @property {string} id - The unique identifier for the collection.
+   * @property {string} [first] - The URL of the first page of the collection.
+   * @property {string} [partOf] - The URL of the main collection that this page is part of.
+   * @property {string} [next] - The URL of the next page of the collection.
+   * @property {string} [prev] - The URL of the previous page of the collection.
+   * @property {Array<Object>} [orderedItems] - An array of ordered items in the collection.
+   * @property {Array<string>} ['@context'] - The context of the collection.
+   */
+  const collection = {
+    type: 'OrderedCollection',
+    totalItems: total,
+    id: outboxUrl,
+    '@context': ['https://www.w3.org/ns/activitystreams']
+  };
+
+  // Check if the 'offset' query parameter is a valid number
+  if (isNaN(req.query.offset)) {
+    collection.first = `${outboxUrl}?offset=0`;
+  } else {
+    // Adjust collection properties for paginated results
+    const offset = parseInt(req.query.offset);
+    collection.type = 'OrderedCollectionPage';
+    collection.id = `${outboxUrl}?offset=${offset}`;
+    collection.partOf = outboxUrl;
+    collection.next = `${outboxUrl}?offset=${offset + 10}`;
+    // todo: stop at 0
+    if (offset - 10 > 0) {
+      collection.prev = `${outboxUrl}?offset=${offset - 10}`;
+    } else {
+      collection.first = `${outboxUrl}?offset=0`;
+    }
+
+    // Transform each post into an ordered item in the collection
+    collection.orderedItems = posts;
+    collection.orderedItems = collection.orderedItems.map(activity => {
+      return {
+        id: `${activity.id}/activity`,
+        type: 'Create',
+        actor: activity.attributedTo,
+        published: activity.published,
+        to: activity.to,
+        cc: activity.cc,
+        object: activity
+      };
+    });
+  }
+
+  // Send the outbox collection in the response
+  res.json(collection);
+});
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.2 on Thu Dec 14 2023 18:13:17 GMT-0800 (Pacific Standard Time) +
+ + + + + diff --git a/docs/public.js.html b/docs/public.js.html new file mode 100644 index 00000000..c1fe11c3 --- /dev/null +++ b/docs/public.js.html @@ -0,0 +1,231 @@ + + + + + JSDoc: Source: public.js + + + + + + + + + + +
+ +

Source: public.js

+ + + + + + +
+
+
import express from 'express';
+import debug from 'debug';
+import RSS from 'rss-generator';
+import dotenv from 'dotenv';
+
+import { getNote, isMyPost, getAccount, getOutboxPosts, ifAccount } from '../lib/account.js';
+import { getActivity, getLikesForNote, getReplyCountForNote } from '../lib/notes.js';
+import { INDEX } from '../lib/storage.js';
+import { ActivityPub } from '../lib/ActivityPub.js';
+
+import { fetchUser } from '../lib/users.js';
+export const router = express.Router();
+dotenv.config();
+
+const { USER_NAME, DOMAIN } = process.env;
+
+const logger = debug('notes');
+
+/**
+ * publish the post to go up the stream
+ * check all the posts below and above the threads
+ */
+const unrollThread = async (noteId, results = [], ascend = true, descend = true) => {
+  let post, actor;
+  let stats;
+  if (
+    isMyPost({
+      id: noteId
+    })
+  ) {
+    try {
+      post = await getNote(noteId);
+      actor = ActivityPub.actor;
+      const likes = getLikesForNote(post.id);
+      stats = {
+        likes: likes.likes.length,
+        boosts: likes.boosts.length,
+        replies: getReplyCountForNote(post.id)
+      };
+    } catch (err) {
+      logger('could not fetch own post in thread', err);
+    }
+  } else {
+    try {
+      post = await getActivity(noteId);
+      const account = await fetchUser(post.attributedTo);
+      actor = account.actor;
+    } catch (err) {
+      logger('Could not load a post in a thread. Possibly deleted.', err);
+    }
+  }
+
+  // can only check up stream if you can look at the post itself.
+  // if it has been deleted, that info is lost.
+  if (post) {
+    results.push({
+      stats,
+      note: post,
+      actor
+    });
+
+    // if this is a reply, get the parent and any other parents straight up the chain
+    // this does NOT get replies to those parents that are not part of the active thread right now.
+    if (ascend && post.inReplyTo) {
+      try {
+        await unrollThread(post.inReplyTo, results, true, false);
+      } catch (err) {
+        logger('Failed to unroll thread parents.', err);
+      }
+    }
+  }
+
+  // now, find all posts that are below this one...
+  if (descend) {
+    const replies = INDEX.filter(p => p.inReplyTo === noteId);
+    for (let r = 0; r < replies.length; r++) {
+      try {
+        await unrollThread(replies[r].id, results, false, true);
+      } catch (err) {
+        logger('Failed to unroll thread children', err);
+      }
+    }
+  }
+
+  return results;
+};
+
+/**
+ * Renders the home page with the outbox posts fetched through the api
+ */
+router.get('/', async (req, res) => {
+  if (!ifAccount()) {
+    console.log('No account found. Redirecting to account creation.');
+    res.redirect('/private');
+  }
+  const offset = parseInt(req.query.offset) || 0;
+  const { posts } = await getOutboxPosts(offset);
+
+  const myaccount = getAccount();
+  ActivityPub.account = myaccount;
+  const actor = ActivityPub.actor;
+
+  res.render('public/home', {
+    me: ActivityPub.actor,
+    actor,
+    activitystream: posts,
+    layout: 'public',
+    next: offset + posts.length,
+    domain: DOMAIN,
+    user: USER_NAME
+  });
+});
+
+/**
+ * Fetch the feed for the user and display it in the html
+ */
+router.get('/feed', async (req, res) => {
+  const {
+    // total,
+    posts
+  } = await getOutboxPosts(0);
+
+  const feed = new RSS({
+    title: `${USER_NAME}@${DOMAIN}`,
+    site_url: DOMAIN,
+    pubDate: posts[0].published
+  });
+
+  posts.forEach(post => {
+    /* loop over data and add to feed */
+    feed.item({
+      title: post.subject,
+      description: post.content,
+      url: post.url,
+      date: post.published // any format that js Date can parse.
+    });
+  });
+
+  res.set('Content-Type', 'text/xml');
+  res.send(
+    feed.xml({
+      indent: true
+    })
+  );
+});
+
+router.get('/notes/:guid', async (req, res) => {
+  const guid = req.params.guid;
+
+  if (!guid) {
+    return res.status(400).send('Bad request.');
+  } else {
+    const actor = ActivityPub.actor;
+    const note = await getNote(`https://${DOMAIN}/m/${guid}`);
+    if (note === undefined) {
+      return res.status(404).send(`No record found for ${guid}.`);
+    } else {
+      const notes = await unrollThread(note.id);
+      notes.sort((a, b) => {
+        const ad = new Date(a.note.published).getTime();
+        const bd = new Date(b.note.published).getTime();
+        if (ad > bd) {
+          return 1;
+        } else if (ad < bd) {
+          return -1;
+        } else {
+          return 0;
+        }
+      });
+      res.render('public/note', {
+        me: ActivityPub.actor,
+        actor,
+        activitystream: notes,
+        layout: 'public',
+        domain: DOMAIN,
+        user: USER_NAME
+      });
+    }
+  }
+});
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.2 on Thu Dec 14 2023 18:13:17 GMT-0800 (Pacific Standard Time) +
+ + + + + diff --git a/docs/scripts/linenumber.js b/docs/scripts/linenumber.js new file mode 100644 index 00000000..f355ce24 --- /dev/null +++ b/docs/scripts/linenumber.js @@ -0,0 +1,25 @@ +/* global document */ +(() => { + const source = document.getElementsByClassName('prettyprint source linenums'); + let i = 0; + let lineNumber = 0; + let lineId; + let lines; + let totalLines; + let anchorHash; + + if (source && source[0]) { + anchorHash = document.location.hash.substring(1); + lines = source[0].getElementsByTagName('li'); + totalLines = lines.length; + + for (; i < totalLines; i++) { + lineNumber++; + lineId = `line${lineNumber}`; + lines[i].id = lineId; + if (lineId === anchorHash) { + lines[i].className += ' selected'; + } + } + } +})(); diff --git a/docs/scripts/prettify/Apache-License-2.0.txt b/docs/scripts/prettify/Apache-License-2.0.txt new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/docs/scripts/prettify/Apache-License-2.0.txt @@ -0,0 +1,202 @@ + + 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/docs/scripts/prettify/lang-css.js b/docs/scripts/prettify/lang-css.js new file mode 100644 index 00000000..7f407959 --- /dev/null +++ b/docs/scripts/prettify/lang-css.js @@ -0,0 +1,23 @@ +PR.registerLangHandler( + PR.createSimpleLexer( + [['pln', /^[\t\n\f\r ]+/, null, ' \t\r\n ']], + [ + ['str', /^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/, null], + ['str', /^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/, null], + ['lang-css-str', /^url\(([^"')]*)\)/i], + ['kwd', /^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i, null], + ['lang-css-kw', /^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i], + ['com', /^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//], + ['com', /^(?:<\!--|--\>)/], + ['lit', /^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i], + ['lit', /^#[\da-f]{3,6}/i], + ['pln', /^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i], + ['pun', /^[^\s\w"']+/] + ] + ), + ['css'] +); +PR.registerLangHandler(PR.createSimpleLexer([], [['kwd', /^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]), [ + 'css-kw' +]); +PR.registerLangHandler(PR.createSimpleLexer([], [['str', /^[^"')]+/]]), ['css-str']); diff --git a/docs/scripts/prettify/prettify.js b/docs/scripts/prettify/prettify.js new file mode 100644 index 00000000..4b5eb69d --- /dev/null +++ b/docs/scripts/prettify/prettify.js @@ -0,0 +1,588 @@ +var q = null; +window.PR_SHOULD_USE_CONTINUATION = !0; +(function () { + function L(a) { + function m(a) { + var f = a.charCodeAt(0); + if (f !== 92) return f; + var b = a.charAt(1); + return (f = r[b]) + ? f + : '0' <= b && b <= '7' + ? parseInt(a.substring(1), 8) + : b === 'u' || b === 'x' + ? parseInt(a.substring(2), 16) + : a.charCodeAt(1); + } + function e(a) { + if (a < 32) return (a < 16 ? '\\x0' : '\\x') + a.toString(16); + a = String.fromCharCode(a); + if (a === '\\' || a === '-' || a === '[' || a === ']') a = '\\' + a; + return a; + } + function h(a) { + for ( + var f = a + .substring(1, a.length - 1) + .match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g), + a = [], + b = [], + o = f[0] === '^', + c = o ? 1 : 0, + i = f.length; + c < i; + ++c + ) { + var j = f[c]; + if (/\\[bdsw]/i.test(j)) a.push(j); + else { + var j = m(j), + d; + c + 2 < i && '-' === f[c + 1] ? ((d = m(f[c + 2])), (c += 2)) : (d = j); + b.push([j, d]); + d < 65 || + j > 122 || + (d < 65 || j > 90 || b.push([Math.max(65, j) | 32, Math.min(d, 90) | 32]), + d < 97 || j > 122 || b.push([Math.max(97, j) & -33, Math.min(d, 122) & -33])); + } + } + b.sort(function (a, f) { + return a[0] - f[0] || f[1] - a[1]; + }); + f = []; + j = [NaN, NaN]; + for (c = 0; c < b.length; ++c) (i = b[c]), i[0] <= j[1] + 1 ? (j[1] = Math.max(j[1], i[1])) : f.push((j = i)); + b = ['[']; + o && b.push('^'); + b.push.apply(b, a); + for (c = 0; c < f.length; ++c) + (i = f[c]), b.push(e(i[0])), i[1] > i[0] && (i[1] + 1 > i[0] && b.push('-'), b.push(e(i[1]))); + b.push(']'); + return b.join(''); + } + function y(a) { + for ( + var f = a.source.match( + /\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g + ), + b = f.length, + d = [], + c = 0, + i = 0; + c < b; + ++c + ) { + var j = f[c]; + j === '(' ? ++i : '\\' === j.charAt(0) && (j = +j.substring(1)) && j <= i && (d[j] = -1); + } + for (c = 1; c < d.length; ++c) -1 === d[c] && (d[c] = ++t); + for (i = c = 0; c < b; ++c) + (j = f[c]), + j === '(' + ? (++i, d[i] === void 0 && (f[c] = '(?:')) + : '\\' === j.charAt(0) && (j = +j.substring(1)) && j <= i && (f[c] = '\\' + d[i]); + for (i = c = 0; c < b; ++c) '^' === f[c] && '^' !== f[c + 1] && (f[c] = ''); + if (a.ignoreCase && s) + for (c = 0; c < b; ++c) + (j = f[c]), + (a = j.charAt(0)), + j.length >= 2 && a === '[' + ? (f[c] = h(j)) + : a !== '\\' && + (f[c] = j.replace(/[A-Za-z]/g, function (a) { + a = a.charCodeAt(0); + return '[' + String.fromCharCode(a & -33, a | 32) + ']'; + })); + return f.join(''); + } + for (var t = 0, s = !1, l = !1, p = 0, d = a.length; p < d; ++p) { + var g = a[p]; + if (g.ignoreCase) l = !0; + else if (/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi, ''))) { + s = !0; + l = !1; + break; + } + } + for (var r = { b: 8, t: 9, n: 10, v: 11, f: 12, r: 13 }, n = [], p = 0, d = a.length; p < d; ++p) { + g = a[p]; + if (g.global || g.multiline) throw Error('' + g); + n.push('(?:' + y(g) + ')'); + } + return RegExp(n.join('|'), l ? 'gi' : 'g'); + } + function M(a) { + function m(a) { + switch (a.nodeType) { + case 1: + if (e.test(a.className)) break; + for (var g = a.firstChild; g; g = g.nextSibling) m(g); + g = a.nodeName; + if ('BR' === g || 'LI' === g) (h[s] = '\n'), (t[s << 1] = y++), (t[(s++ << 1) | 1] = a); + break; + case 3: + case 4: + (g = a.nodeValue), + g.length && + ((g = p ? g.replace(/\r\n?/g, '\n') : g.replace(/[\t\n\r ]+/g, ' ')), + (h[s] = g), + (t[s << 1] = y), + (y += g.length), + (t[(s++ << 1) | 1] = a)); + } + } + var e = /(?:^|\s)nocode(?:\s|$)/, + h = [], + y = 0, + t = [], + s = 0, + l; + a.currentStyle + ? (l = a.currentStyle.whiteSpace) + : window.getComputedStyle && (l = document.defaultView.getComputedStyle(a, q).getPropertyValue('white-space')); + var p = l && 'pre' === l.substring(0, 3); + m(a); + return { a: h.join('').replace(/\n$/, ''), c: t }; + } + function B(a, m, e, h) { + m && ((a = { a: m, d: a }), e(a), h.push.apply(h, a.e)); + } + function x(a, m) { + function e(a) { + for (var l = a.d, p = [l, 'pln'], d = 0, g = a.a.match(y) || [], r = {}, n = 0, z = g.length; n < z; ++n) { + var f = g[n], + b = r[f], + o = void 0, + c; + if (typeof b === 'string') c = !1; + else { + var i = h[f.charAt(0)]; + if (i) (o = f.match(i[1])), (b = i[0]); + else { + for (c = 0; c < t; ++c) + if (((i = m[c]), (o = f.match(i[1])))) { + b = i[0]; + break; + } + o || (b = 'pln'); + } + if ((c = b.length >= 5 && 'lang-' === b.substring(0, 5)) && !(o && typeof o[1] === 'string')) + (c = !1), (b = 'src'); + c || (r[f] = b); + } + i = d; + d += f.length; + if (c) { + c = o[1]; + var j = f.indexOf(c), + k = j + c.length; + o[2] && ((k = f.length - o[2].length), (j = k - c.length)); + b = b.substring(5); + B(l + i, f.substring(0, j), e, p); + B(l + i + j, c, C(b, c), p); + B(l + i + k, f.substring(k), e, p); + } else p.push(l + i, b); + } + a.e = p; + } + var h = {}, + y; + (function () { + for (var e = a.concat(m), l = [], p = {}, d = 0, g = e.length; d < g; ++d) { + var r = e[d], + n = r[3]; + if (n) for (var k = n.length; --k >= 0; ) h[n.charAt(k)] = r; + r = r[1]; + n = '' + r; + p.hasOwnProperty(n) || (l.push(r), (p[n] = q)); + } + l.push(/[\S\s]/); + y = L(l); + })(); + var t = m.length; + return e; + } + function u(a) { + var m = [], + e = []; + a.tripleQuotedStrings + ? m.push([ + 'str', + /^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/, + q, + '\'"' + ]) + : a.multiLineStrings + ? m.push([ + 'str', + /^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, + q, + '\'"`' + ]) + : m.push(['str', /^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/, q, '"\'']); + a.verbatimStrings && e.push(['str', /^@"(?:[^"]|"")*(?:"|$)/, q]); + var h = a.hashComments; + h && + (a.cStyleComments + ? (h > 1 + ? m.push(['com', /^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/, q, '#']) + : m.push([ + 'com', + /^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/, + q, + '#' + ]), + e.push(['str', /^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/, q])) + : m.push(['com', /^#[^\n\r]*/, q, '#'])); + a.cStyleComments && (e.push(['com', /^\/\/[^\n\r]*/, q]), e.push(['com', /^\/\*[\S\s]*?(?:\*\/|$)/, q])); + a.regexLiterals && + e.push([ + 'lang-regex', + /^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/ + ]); + (h = a.types) && e.push(['typ', h]); + a = ('' + a.keywords).replace(/^ | $/g, ''); + a.length && e.push(['kwd', RegExp('^(?:' + a.replace(/[\s,]+/g, '|') + ')\\b'), q]); + m.push(['pln', /^\s+/, q, ' \r\n\t\xa0']); + e.push( + ['lit', /^@[$_a-z][\w$@]*/i, q], + ['typ', /^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/, q], + ['pln', /^[$_a-z][\w$@]*/i, q], + ['lit', /^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i, q, '0123456789'], + ['pln', /^\\[\S\s]?/, q], + ['pun', /^.[^\s\w"-$'./@\\`]*/, q] + ); + return x(m, e); + } + function D(a, m) { + function e(a) { + switch (a.nodeType) { + case 1: + if (k.test(a.className)) break; + if ('BR' === a.nodeName) h(a), a.parentNode && a.parentNode.removeChild(a); + else for (a = a.firstChild; a; a = a.nextSibling) e(a); + break; + case 3: + case 4: + if (p) { + var b = a.nodeValue, + d = b.match(t); + if (d) { + var c = b.substring(0, d.index); + a.nodeValue = c; + (b = b.substring(d.index + d[0].length)) && a.parentNode.insertBefore(s.createTextNode(b), a.nextSibling); + h(a); + c || a.parentNode.removeChild(a); + } + } + } + } + function h(a) { + function b(a, d) { + var e = d ? a.cloneNode(!1) : a, + f = a.parentNode; + if (f) { + var f = b(f, 1), + g = a.nextSibling; + f.appendChild(e); + for (var h = g; h; h = g) (g = h.nextSibling), f.appendChild(h); + } + return e; + } + for (; !a.nextSibling; ) if (((a = a.parentNode), !a)) return; + for (var a = b(a.nextSibling, 0), e; (e = a.parentNode) && e.nodeType === 1; ) a = e; + d.push(a); + } + var k = /(?:^|\s)nocode(?:\s|$)/, + t = /\r\n?|\n/, + s = a.ownerDocument, + l; + a.currentStyle + ? (l = a.currentStyle.whiteSpace) + : window.getComputedStyle && (l = s.defaultView.getComputedStyle(a, q).getPropertyValue('white-space')); + var p = l && 'pre' === l.substring(0, 3); + for (l = s.createElement('LI'); a.firstChild; ) l.appendChild(a.firstChild); + for (var d = [l], g = 0; g < d.length; ++g) e(d[g]); + m === (m | 0) && d[0].setAttribute('value', m); + var r = s.createElement('OL'); + r.className = 'linenums'; + for (var n = Math.max(0, (m - 1) | 0) || 0, g = 0, z = d.length; g < z; ++g) + (l = d[g]), + (l.className = 'L' + ((g + n) % 10)), + l.firstChild || l.appendChild(s.createTextNode('\xa0')), + r.appendChild(l); + a.appendChild(r); + } + function k(a, m) { + for (var e = m.length; --e >= 0; ) { + var h = m[e]; + A.hasOwnProperty(h) ? window.console && console.warn('cannot override language handler %s', h) : (A[h] = a); + } + } + function C(a, m) { + if (!a || !A.hasOwnProperty(a)) a = /^\s*= o && (h += 2); + e >= c && (a += 2); + } + } catch (w) { + 'console' in window && console.log(w && w.stack ? w.stack : w); + } + } + var v = ['break,continue,do,else,for,if,return,while'], + w = [ + [ + v, + 'auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile' + ], + 'catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof' + ], + F = [ + w, + 'alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where' + ], + G = [ + w, + 'abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient' + ], + H = [ + G, + 'as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var' + ], + w = [w, 'debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN'], + I = [ + v, + 'and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None' + ], + J = [ + v, + 'alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END' + ], + v = [v, 'case,done,elif,esac,eval,fi,function,in,local,set,then,until'], + K = + /^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/, + N = /\S/, + O = u({ + keywords: [ + F, + H, + w, + 'caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END' + + I, + J, + v + ], + hashComments: !0, + cStyleComments: !0, + multiLineStrings: !0, + regexLiterals: !0 + }), + A = {}; + k(O, ['default-code']); + k( + x( + [], + [ + ['pln', /^[^]*(?:>|$)/], + ['com', /^<\!--[\S\s]*?(?:--\>|$)/], + ['lang-', /^<\?([\S\s]+?)(?:\?>|$)/], + ['lang-', /^<%([\S\s]+?)(?:%>|$)/], + ['pun', /^(?:<[%?]|[%?]>)/], + ['lang-', /^]*>([\S\s]+?)<\/xmp\b[^>]*>/i], + ['lang-js', /^]*>([\S\s]*?)(<\/script\b[^>]*>)/i], + ['lang-css', /^]*>([\S\s]*?)(<\/style\b[^>]*>)/i], + ['lang-in.tag', /^(<\/?[a-z][^<>]*>)/i] + ] + ), + ['default-markup', 'htm', 'html', 'mxml', 'xhtml', 'xml', 'xsl'] + ); + k( + x( + [ + ['pln', /^\s+/, q, ' \t\r\n'], + ['atv', /^(?:"[^"]*"?|'[^']*'?)/, q, '"\''] + ], + [ + ['tag', /^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i], + ['atn', /^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i], + ['lang-uq.val', /^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/], + ['pun', /^[/<->]+/], + ['lang-js', /^on\w+\s*=\s*"([^"]+)"/i], + ['lang-js', /^on\w+\s*=\s*'([^']+)'/i], + ['lang-js', /^on\w+\s*=\s*([^\s"'>]+)/i], + ['lang-css', /^style\s*=\s*"([^"]+)"/i], + ['lang-css', /^style\s*=\s*'([^']+)'/i], + ['lang-css', /^style\s*=\s*([^\s"'>]+)/i] + ] + ), + ['in.tag'] + ); + k(x([], [['atv', /^[\S\s]+/]]), ['uq.val']); + k(u({ keywords: F, hashComments: !0, cStyleComments: !0, types: K }), ['c', 'cc', 'cpp', 'cxx', 'cyc', 'm']); + k(u({ keywords: 'null,true,false' }), ['json']); + k(u({ keywords: H, hashComments: !0, cStyleComments: !0, verbatimStrings: !0, types: K }), ['cs']); + k(u({ keywords: G, cStyleComments: !0 }), ['java']); + k(u({ keywords: v, hashComments: !0, multiLineStrings: !0 }), ['bsh', 'csh', 'sh']); + k(u({ keywords: I, hashComments: !0, multiLineStrings: !0, tripleQuotedStrings: !0 }), ['cv', 'py']); + k( + u({ + keywords: + 'caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END', + hashComments: !0, + multiLineStrings: !0, + regexLiterals: !0 + }), + ['perl', 'pl', 'pm'] + ); + k(u({ keywords: J, hashComments: !0, multiLineStrings: !0, regexLiterals: !0 }), ['rb']); + k(u({ keywords: w, cStyleComments: !0, regexLiterals: !0 }), ['js']); + k( + u({ + keywords: + 'all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes', + hashComments: 3, + cStyleComments: !0, + multilineStrings: !0, + tripleQuotedStrings: !0, + regexLiterals: !0 + }), + ['coffee'] + ); + k(x([], [['str', /^[\S\s]+/]]), ['regex']); + window.prettyPrintOne = function (a, m, e) { + var h = document.createElement('PRE'); + h.innerHTML = a; + e && D(h, e); + E({ g: m, i: e, h: h }); + return h.innerHTML; + }; + window.prettyPrint = function (a) { + function m() { + for (var e = window.PR_SHOULD_USE_CONTINUATION ? l.now() + 250 : Infinity; p < h.length && l.now() < e; p++) { + var n = h[p], + k = n.className; + if (k.indexOf('prettyprint') >= 0) { + var k = k.match(g), + f, + b; + if ((b = !k)) { + b = n; + for (var o = void 0, c = b.firstChild; c; c = c.nextSibling) + var i = c.nodeType, o = i === 1 ? (o ? b : c) : i === 3 ? (N.test(c.nodeValue) ? b : o) : o; + b = (f = o === b ? void 0 : o) && 'CODE' === f.tagName; + } + b && (k = f.className.match(g)); + k && (k = k[1]); + b = !1; + for (o = n.parentNode; o; o = o.parentNode) + if ( + (o.tagName === 'pre' || o.tagName === 'code' || o.tagName === 'xmp') && + o.className && + o.className.indexOf('prettyprint') >= 0 + ) { + b = !0; + break; + } + b || + ((b = (b = n.className.match(/\blinenums\b(?::(\d+))?/)) ? (b[1] && b[1].length ? +b[1] : !0) : !1) && + D(n, b), + (d = { g: k, h: n, i: b }), + E(d)); + } + } + p < h.length ? setTimeout(m, 250) : a && a(); + } + for ( + var e = [ + document.getElementsByTagName('pre'), + document.getElementsByTagName('code'), + document.getElementsByTagName('xmp') + ], + h = [], + k = 0; + k < e.length; + ++k + ) + for (var t = 0, s = e[k].length; t < s; ++t) h.push(e[k][t]); + var e = q, + l = Date; + l.now || + (l = { + now: function () { + return +new Date(); + } + }); + var p = 0, + d, + g = /\blang(?:uage)?-([\w.]+)(?!\S)/; + m(); + }; + window.PR = { + createSimpleLexer: x, + registerLangHandler: k, + sourceDecorator: u, + PR_ATTRIB_NAME: 'atn', + PR_ATTRIB_VALUE: 'atv', + PR_COMMENT: 'com', + PR_DECLARATION: 'dec', + PR_KEYWORD: 'kwd', + PR_LITERAL: 'lit', + PR_NOCODE: 'nocode', + PR_PLAIN: 'pln', + PR_PUNCTUATION: 'pun', + PR_SOURCE: 'src', + PR_STRING: 'str', + PR_TAG: 'tag', + PR_TYPE: 'typ' + }; +})(); diff --git a/docs/storage.js.html b/docs/storage.js.html new file mode 100644 index 00000000..65417867 --- /dev/null +++ b/docs/storage.js.html @@ -0,0 +1,457 @@ + + + + + JSDoc: Source: storage.js + + + + + + + + + + +
+ +

Source: storage.js

+ + + + + + +
+
+
import fs from 'fs';
+import glob from 'glob';
+import path from 'path';
+import md5 from 'md5';
+import { DEFAULT_SETTINGS } from './prefs.js';
+
+import debug from 'debug';
+import dotenv from 'dotenv';
+
+const logger = debug('ono:storage');
+dotenv.config();
+
+export const dataDir = path.resolve('./', '.data/');
+export const pathToFiles = path.resolve(dataDir, 'activitystream/');
+export const pathToPosts = path.resolve(dataDir, 'posts/');
+export const pathToUsers = path.resolve(dataDir, 'users/');
+export const pathToDMs = path.resolve(dataDir, 'dms/');
+
+export const prefsFile = path.resolve(dataDir, 'prefs.json');
+export const followersFile = path.resolve(dataDir, 'followers.json');
+export const followingFile = path.resolve(dataDir, 'following.json');
+export const notificationsFile = path.resolve(dataDir, 'notifications.json');
+export const likesFile = path.resolve(dataDir, 'likes.json');
+export const boostsFile = path.resolve(dataDir, 'boosts.json');
+export const blocksFile = path.resolve(dataDir, 'blocks.json');
+export const accountFile = path.resolve(dataDir, 'account.json');
+
+const { DOMAIN } = process.env;
+
+export const INDEX = [];
+export const CACHE = {};
+
+const cacheMax = 60 * 5 * 1000; // 5 minutes
+const cacheMin = 30 * 1000; // 30 seconds
+
+/**
+ * Function to zero-pad a number.
+ * @param {number} num - The number to zero-pad.
+ * @returns {string} - The zero-padded number as a string.
+ */
+const zeroPad = num => {
+  if (num < 10) {
+    return `0${num}`;
+  } else return num;
+};
+
+/**
+ * Checks if an activity belongs to the current user.
+ * @param {string} activityId - The ID of the activity.
+ * @returns {boolean} - True if the activity belongs to the current user, false otherwise.
+ */
+export const isMyPost = activityId => {
+  return activityId.startsWith(`https://${DOMAIN}/m/`);
+};
+
+/**
+ * Checks if an activity is in the INDEX array.
+ * @param {string} id - The ID of the activity.
+ * @returns {boolean} - True if the activity is indexed, false otherwise.
+ */
+export const isIndexed = id => {
+  return INDEX.some(p => id === p.id);
+};
+
+/**
+ * Retrieves activity info from the index based on the activity ID.
+ * @param {string} id - The ID of the activity.
+ * @returns {Object|boolean} - The activity information if found, otherwise false.
+ */
+export const fromIndex = id => {
+  return INDEX.find(p => id === p.id) || false;
+};
+
+/**
+ * Gets user preferences.
+ * @returns {Object} - User preferences.
+ */
+export const getPrefs = () => {
+  return readJSONDictionary(prefsFile, DEFAULT_SETTINGS);
+};
+
+/**
+ * Updates user preferences.
+ * @param {Object} prefs - The new user preferences.
+ * @returns {void}
+ */
+export const updatePrefs = prefs => {
+  return writeJSONDictionary(prefsFile, prefs);
+};
+
+/**
+ * Adds a failure entry to the index.
+ * @param {Object} note - The note object.
+ * @param {string} type - The type of failure (default is 'fail').
+ * @returns {void}
+ */
+export const addFailureToIndex = (note, type = 'fail') => {
+  INDEX.push({
+    type,
+    id: note.id,
+    published: note.time,
+    status: note.status
+  });
+};
+
+/**
+ * Adds an activity entry to the index.
+ * @param {Object} note - The note object.
+ * @param {string} type - The type of activity (default is 'activity').
+ * @returns {void}
+ */
+export const addActivityToIndex = (note, type = 'activity') => {
+  INDEX.push({
+    type,
+    id: note.id,
+    actor: note.attributedTo || note.actor,
+    published: new Date(note.published).getTime(),
+    inReplyTo: note.inReplyTo
+  });
+};
+
+/**
+ * Deletes an activity entry from the index.
+ * @param {string} id - The ID of the activity to be deleted.
+ * @returns {void}
+ */
+export const deleteActivityFromIndex = id => {
+  const n = INDEX.findIndex(idx => idx.id === id);
+  if (n >= 0) {
+    INDEX.splice(n, 1);
+  }
+};
+
+/**
+ * Gets the file name for a given activity ID.
+ * @param {string} activityId - The ID of the activity.
+ * @returns {string} - The file name.
+ */
+export const getFileName = activityId => {
+  // first check cache!
+  let meta;
+  if (CACHE[activityId]) {
+    meta = CACHE[activityId].contents;
+  } else {
+    meta = INDEX.find(m => m.id === activityId);
+    if (!meta) {
+      console.error('id not found in index!', activityId);
+      throw new Error('id not found in index');
+    }
+  }
+
+  const rootPath = isMyPost(activityId) ? pathToPosts : pathToFiles;
+
+  // create a dated subfolder
+  const datestamp = new Date(meta.published);
+  const folder = datestamp.getFullYear() + '/' + zeroPad(datestamp.getMonth() + 1) + '-' + zeroPad(datestamp.getDate());
+  return path.resolve(rootPath, folder, `${md5(meta.id)}.json`);
+};
+
+/**
+ * Gets the file name for the likes associated with a given activity ID.
+ * @param {string} activityId - The ID of the activity.
+ * @returns {string} - The file name for likes.
+ */
+export const getLikesFileName = activityId => {
+  // first check cache!
+  let meta;
+  if (CACHE[activityId]) {
+    meta = CACHE[activityId].contents;
+  } else {
+    meta = INDEX.find(m => m.id === activityId);
+    if (!meta) {
+      console.error('id not found in index!', activityId);
+      throw new Error('id not found in index');
+    }
+  }
+
+  const rootPath = pathToPosts;
+
+  // create a dated subfolder
+  const datestamp = new Date(meta.published);
+  const folder = datestamp.getFullYear() + '/' + zeroPad(datestamp.getMonth() + 1) + '-' + zeroPad(datestamp.getDate());
+  return path.resolve(rootPath, folder, `${md5(meta.id)}.likes.json`);
+};
+
+/**
+ * Creates a file name for a given activity.
+ * @param {Object} activity - The activity object.
+ * @returns {string} - The file name.
+ */
+export const createFileName = activity => {
+  // create a dated subfolder
+  const datestamp = new Date(activity.published);
+  const folder = datestamp.getFullYear() + '/' + zeroPad(datestamp.getMonth() + 1) + '-' + zeroPad(datestamp.getDate());
+
+  const rootPath = isMyPost(activity.id) ? pathToPosts : pathToFiles;
+  // ensure the subfolder is prsent
+  if (!fs.existsSync(path.resolve(rootPath, folder))) {
+    fs.mkdirSync(path.resolve(rootPath, folder), {
+      recursive: true
+    });
+  }
+  return path.resolve(rootPath, folder, `${md5(activity.id)}.json`);
+};
+
+/**
+ * Clears expired entries from the cache.
+ * @returns {void}
+ */
+const cacheExpire = () => {
+  const now = new Date().getTime();
+  for (const key in CACHE) {
+    if (CACHE[key].lastAccess < now - cacheMin) {
+      logger('clearing cache for', key);
+      delete CACHE[key];
+    }
+  }
+};
+
+/**
+ * Interval function for the garbage collector to clear expired cache entries.
+ * @type {number}
+ */
+const garbageCollector = setInterval(() => {
+  cacheExpire();
+}, cacheMin);
+
+logger('Garbage collector interval', garbageCollector);
+
+/**
+ * Builds the initial index by reading data from files.
+ * @returns {Promise<Array<Object>>} - A promise that resolves with the built index.
+ */
+const buildIndex = () => {
+  return new Promise((resolve, reject) => {
+    glob(path.join(pathToFiles, '**/*.json'), async (err, files) => {
+      if (err) {
+        console.error(err);
+        reject(err);
+      }
+
+      for (const f of files) {
+        try {
+          const post = JSON.parse(fs.readFileSync(path.resolve(pathToFiles, f)));
+          addActivityToIndex(post);
+        } catch (err) {
+          console.error('failed to parse', f);
+          console.error(err);
+        }
+      }
+
+      glob(path.join(pathToPosts, '**/*.json'), async (err, files) => {
+        if (err) {
+          console.error(err);
+          reject(err);
+        }
+
+        for (const f of files) {
+          try {
+            if (!f.includes('likes')) {
+              const post = JSON.parse(fs.readFileSync(path.resolve(pathToFiles, f)));
+              addActivityToIndex(post, 'note');
+            }
+          } catch (err) {
+            console.error('failed to parse', f);
+            console.error(err);
+          }
+        }
+
+        resolve(INDEX);
+      });
+    });
+  });
+};
+
+/**
+ * Searches for known users based on a query string.
+ * @param {string} query - The search query.
+ * @returns {Promise<Array<Object>>} - A promise that resolves with the search results.
+ */
+export const searchKnownUsers = async query => {
+  return new Promise((resolve, reject) => {
+    glob(path.join(pathToUsers, '**/*.json'), async (err, files) => {
+      if (err) {
+        console.error(err);
+        reject(err);
+      }
+      const results = [];
+      for (const f of files) {
+        try {
+          const user = JSON.parse(fs.readFileSync(path.resolve(pathToUsers, f)));
+          if (
+            user.actor?.id?.toLowerCase().includes(query) ||
+            user.actor?.preferredUsername?.toLowerCase().includes(query) ||
+            user.actor?.name?.toLowerCase().includes(query) ||
+            user.actor?.url?.toLowerCase().includes(query)
+          ) {
+            results.push(user.actor);
+          }
+        } catch (err) {
+          console.error('failed to parse', f);
+          console.error(err);
+        }
+      }
+      resolve(results);
+    });
+  });
+};
+
+/**
+ * Ensures the existence of data folders and default settings.
+ * @returns {void}
+ */
+const ensureDataFolder = () => {
+  if (!fs.existsSync(path.resolve(pathToPosts))) {
+    logger('mkdir', pathToPosts);
+    fs.mkdirSync(path.resolve(pathToPosts), {
+      recursive: true
+    });
+  }
+  if (!fs.existsSync(path.resolve(pathToFiles))) {
+    logger('mkdir', pathToFiles);
+    fs.mkdirSync(path.resolve(pathToFiles), {
+      recursive: true
+    });
+  }
+  if (!fs.existsSync(path.resolve(pathToUsers))) {
+    logger('mkdir', pathToUsers);
+    fs.mkdirSync(path.resolve(pathToUsers), {
+      recursive: true
+    });
+  }
+  if (!fs.existsSync(path.resolve(pathToDMs))) {
+    logger('mkdir', pathToDMs);
+    fs.mkdirSync(path.resolve(pathToDMs), {
+      recursive: true
+    });
+  }
+  if (!fs.existsSync(path.resolve(prefsFile))) {
+    logger('create default settings', prefsFile);
+    writeJSONDictionary(prefsFile, DEFAULT_SETTINGS);
+  } else {
+    // todo: validate settings, add any missing keys with default values
+  }
+};
+
+/**
+ * Reads a JSON dictionary from a file path.
+ * @param {string} path - The path to the JSON file.
+ * @param {Array} defaultVal - The default value if the file doesn't exist.
+ * @returns {Array} - The contents of the JSON file.
+ */
+export const readJSONDictionary = (path, defaultVal = []) => {
+  const now = new Date().getTime();
+  if (CACHE[path] && CACHE[path].time > now - cacheMax) {
+    logger('cache hit for', path);
+    CACHE[path].lastAccess = now;
+    return CACHE[path].contents;
+  } else {
+    logger('read from disk', path);
+    let jsonRaw = JSON.stringify(defaultVal);
+    if (fs.existsSync(path)) {
+      jsonRaw = fs.readFileSync(path);
+    }
+    const results = JSON.parse(jsonRaw) || defaultVal;
+    CACHE[path] = {
+      time: now,
+      lastAccess: now,
+      contents: results
+    };
+    return results;
+  }
+};
+
+/**
+ * Deletes a JSON dictionary file.
+ * @param {string} path - The path to the JSON file to be deleted.
+ * @returns {void}
+ */
+export const deleteJSONDictionary = path => {
+  fs.unlinkSync(path);
+  delete CACHE[path];
+};
+
+/**
+ * Writes a JSON dictionary to a file.
+ * @param {string} path - The path to the file.
+ * @param {Object} data - The data to be written.
+ * @returns {void}
+ */
+export const writeJSONDictionary = (path, data) => {
+  const now = new Date().getTime();
+  logger('write cache', path);
+  CACHE[path] = {
+    time: now,
+    lastAccess: now,
+    contents: data
+  };
+  fs.writeFileSync(path, JSON.stringify(data, null, 2));
+};
+
+logger('BUILDING INDEX');
+ensureDataFolder();
+buildIndex().then(() => {
+  logger('INDEX BUILT!');
+});
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.2 on Thu Dec 14 2023 18:11:22 GMT-0800 (Pacific Standard Time) +
+ + + + + diff --git a/docs/styles/jsdoc-default.css b/docs/styles/jsdoc-default.css new file mode 100644 index 00000000..7d1729dc --- /dev/null +++ b/docs/styles/jsdoc-default.css @@ -0,0 +1,358 @@ +@font-face { + font-family: 'Open Sans'; + font-weight: normal; + font-style: normal; + src: url('../fonts/OpenSans-Regular-webfont.eot'); + src: + local('Open Sans'), + local('OpenSans'), + url('../fonts/OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/OpenSans-Regular-webfont.woff') format('woff'), + url('../fonts/OpenSans-Regular-webfont.svg#open_sansregular') format('svg'); +} + +@font-face { + font-family: 'Open Sans Light'; + font-weight: normal; + font-style: normal; + src: url('../fonts/OpenSans-Light-webfont.eot'); + src: + local('Open Sans Light'), + local('OpenSans Light'), + url('../fonts/OpenSans-Light-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/OpenSans-Light-webfont.woff') format('woff'), + url('../fonts/OpenSans-Light-webfont.svg#open_sanslight') format('svg'); +} + +html +{ + overflow: auto; + background-color: #fff; + font-size: 14px; +} + +body +{ + font-family: 'Open Sans', sans-serif; + line-height: 1.5; + color: #4d4e53; + background-color: white; +} + +a, a:visited, a:active { + color: #0095dd; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +header +{ + display: block; + padding: 0px 4px; +} + +tt, code, kbd, samp { + font-family: Consolas, Monaco, 'Andale Mono', monospace; +} + +.class-description { + font-size: 130%; + line-height: 140%; + margin-bottom: 1em; + margin-top: 1em; +} + +.class-description:empty { + margin: 0; +} + +#main { + float: left; + width: 70%; +} + +article dl { + margin-bottom: 40px; +} + +article img { + max-width: 100%; +} + +section +{ + display: block; + background-color: #fff; + padding: 12px 24px; + border-bottom: 1px solid #ccc; + margin-right: 30px; +} + +.variation { + display: none; +} + +.signature-attributes { + font-size: 60%; + color: #aaa; + font-style: italic; + font-weight: lighter; +} + +nav +{ + display: block; + float: right; + margin-top: 28px; + width: 30%; + box-sizing: border-box; + border-left: 1px solid #ccc; + padding-left: 16px; +} + +nav ul { + font-family: 'Lucida Grande', 'Lucida Sans Unicode', arial, sans-serif; + font-size: 100%; + line-height: 17px; + padding: 0; + margin: 0; + list-style-type: none; +} + +nav ul a, nav ul a:visited, nav ul a:active { + font-family: Consolas, Monaco, 'Andale Mono', monospace; + line-height: 18px; + color: #4D4E53; +} + +nav h3 { + margin-top: 12px; +} + +nav li { + margin-top: 6px; +} + +footer { + display: block; + padding: 6px; + margin-top: 12px; + font-style: italic; + font-size: 90%; +} + +h1, h2, h3, h4 { + font-weight: 200; + margin: 0; +} + +h1 +{ + font-family: 'Open Sans Light', sans-serif; + font-size: 48px; + letter-spacing: -2px; + margin: 12px 24px 20px; +} + +h2, h3.subsection-title +{ + font-size: 30px; + font-weight: 700; + letter-spacing: -1px; + margin-bottom: 12px; +} + +h3 +{ + font-size: 24px; + letter-spacing: -0.5px; + margin-bottom: 12px; +} + +h4 +{ + font-size: 18px; + letter-spacing: -0.33px; + margin-bottom: 12px; + color: #4d4e53; +} + +h5, .container-overview .subsection-title +{ + font-size: 120%; + font-weight: bold; + letter-spacing: -0.01em; + margin: 8px 0 3px 0; +} + +h6 +{ + font-size: 100%; + letter-spacing: -0.01em; + margin: 6px 0 3px 0; + font-style: italic; +} + +table +{ + border-spacing: 0; + border: 0; + border-collapse: collapse; +} + +td, th +{ + border: 1px solid #ddd; + margin: 0px; + text-align: left; + vertical-align: top; + padding: 4px 6px; + display: table-cell; +} + +thead tr +{ + background-color: #ddd; + font-weight: bold; +} + +th { border-right: 1px solid #aaa; } +tr > th:last-child { border-right: 1px solid #ddd; } + +.ancestors, .attribs { color: #999; } +.ancestors a, .attribs a +{ + color: #999 !important; + text-decoration: none; +} + +.clear +{ + clear: both; +} + +.important +{ + font-weight: bold; + color: #950B02; +} + +.yes-def { + text-indent: -1000px; +} + +.type-signature { + color: #aaa; +} + +.name, .signature { + font-family: Consolas, Monaco, 'Andale Mono', monospace; +} + +.details { margin-top: 14px; border-left: 2px solid #DDD; } +.details dt { width: 120px; float: left; padding-left: 10px; padding-top: 6px; } +.details dd { margin-left: 70px; } +.details ul { margin: 0; } +.details ul { list-style-type: none; } +.details li { margin-left: 30px; padding-top: 6px; } +.details pre.prettyprint { margin: 0 } +.details .object-value { padding-top: 0; } + +.description { + margin-bottom: 1em; + margin-top: 1em; +} + +.code-caption +{ + font-style: italic; + font-size: 107%; + margin: 0; +} + +.source +{ + border: 1px solid #ddd; + width: 80%; + overflow: auto; +} + +.prettyprint.source { + width: inherit; +} + +.source code +{ + font-size: 100%; + line-height: 18px; + display: block; + padding: 4px 12px; + margin: 0; + background-color: #fff; + color: #4D4E53; +} + +.prettyprint code span.line +{ + display: inline-block; +} + +.prettyprint.linenums +{ + padding-left: 70px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.prettyprint.linenums ol +{ + padding-left: 0; +} + +.prettyprint.linenums li +{ + border-left: 3px #ddd solid; +} + +.prettyprint.linenums li.selected, +.prettyprint.linenums li.selected * +{ + background-color: lightyellow; +} + +.prettyprint.linenums li * +{ + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; +} + +.params .name, .props .name, .name code { + color: #4D4E53; + font-family: Consolas, Monaco, 'Andale Mono', monospace; + font-size: 100%; +} + +.params td.description > p:first-child, +.props td.description > p:first-child +{ + margin-top: 0; + padding-top: 0; +} + +.params td.description > p:last-child, +.props td.description > p:last-child +{ + margin-bottom: 0; + padding-bottom: 0; +} + +.disabled { + color: #454545; +} diff --git a/docs/styles/prettify-jsdoc.css b/docs/styles/prettify-jsdoc.css new file mode 100644 index 00000000..5a2526e3 --- /dev/null +++ b/docs/styles/prettify-jsdoc.css @@ -0,0 +1,111 @@ +/* JSDoc prettify.js theme */ + +/* plain text */ +.pln { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* string content */ +.str { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a keyword */ +.kwd { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a comment */ +.com { + font-weight: normal; + font-style: italic; +} + +/* a type name */ +.typ { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* a literal value */ +.lit { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* punctuation */ +.pun { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* lisp open bracket */ +.opn { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* lisp close bracket */ +.clo { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a markup tag name */ +.tag { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a markup attribute name */ +.atn { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a markup attribute value */ +.atv { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a declaration */ +.dec { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a variable name */ +.var { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* a function name */ +.fun { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; +} diff --git a/docs/styles/prettify-tomorrow.css b/docs/styles/prettify-tomorrow.css new file mode 100644 index 00000000..b6f92a78 --- /dev/null +++ b/docs/styles/prettify-tomorrow.css @@ -0,0 +1,132 @@ +/* Tomorrow Theme */ +/* Original theme - https://github.com/chriskempson/tomorrow-theme */ +/* Pretty printing styles. Used with prettify.js. */ +/* SPAN elements with the classes below are added by prettyprint. */ +/* plain text */ +.pln { + color: #4d4d4c; } + +@media screen { + /* string content */ + .str { + color: #718c00; } + + /* a keyword */ + .kwd { + color: #8959a8; } + + /* a comment */ + .com { + color: #8e908c; } + + /* a type name */ + .typ { + color: #4271ae; } + + /* a literal value */ + .lit { + color: #f5871f; } + + /* punctuation */ + .pun { + color: #4d4d4c; } + + /* lisp open bracket */ + .opn { + color: #4d4d4c; } + + /* lisp close bracket */ + .clo { + color: #4d4d4c; } + + /* a markup tag name */ + .tag { + color: #c82829; } + + /* a markup attribute name */ + .atn { + color: #f5871f; } + + /* a markup attribute value */ + .atv { + color: #3e999f; } + + /* a declaration */ + .dec { + color: #f5871f; } + + /* a variable name */ + .var { + color: #c82829; } + + /* a function name */ + .fun { + color: #4271ae; } } +/* Use higher contrast and text-weight for printable form. */ +@media print, projection { + .str { + color: #060; } + + .kwd { + color: #006; + font-weight: bold; } + + .com { + color: #600; + font-style: italic; } + + .typ { + color: #404; + font-weight: bold; } + + .lit { + color: #044; } + + .pun, .opn, .clo { + color: #440; } + + .tag { + color: #006; + font-weight: bold; } + + .atn { + color: #404; } + + .atv { + color: #060; } } +/* Style */ +/* +pre.prettyprint { + background: white; + font-family: Consolas, Monaco, 'Andale Mono', monospace; + font-size: 12px; + line-height: 1.5; + border: 1px solid #ccc; + padding: 10px; } +*/ + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; } + +/* IE indents via margin-left */ +li.L0, +li.L1, +li.L2, +li.L3, +li.L4, +li.L5, +li.L6, +li.L7, +li.L8, +li.L9 { + /* */ } + +/* Alternate shading for lines */ +li.L1, +li.L3, +li.L5, +li.L7, +li.L9 { + /* */ } diff --git a/docs/theAlgorithm.js.html b/docs/theAlgorithm.js.html new file mode 100644 index 00000000..835a829d --- /dev/null +++ b/docs/theAlgorithm.js.html @@ -0,0 +1,276 @@ + + + + + JSDoc: Source: theAlgorithm.js + + + + + + + + + + +
+ +

Source: theAlgorithm.js

+ + + + + + +
+
+
/** 
+ _______  __   __  _______                                                     
+|       ||  | |  ||       |                                                    
+|_     _||  |_|  ||    ___|                                                    
+  |   |  |       ||   |___                                                     
+  |   |  |       ||    ___|                                                    
+  |   |  |   _   ||   |___                                                     
+  |___|  |__| |__||_______|                                                    
+ _______  ___      _______  _______  ______    ___   _______  __   __  __   __ 
+|   _   ||   |    |       ||       ||    _ |  |   | |       ||  | |  ||  |_|  |
+|  |_|  ||   |    |    ___||   _   ||   | ||  |   | |_     _||  |_|  ||       |
+|       ||   |    |   | __ |  | |  ||   |_||_ |   |   |   |  |       ||       |
+|       ||   |___ |   ||  ||  |_|  ||    __  ||   |   |   |  |       ||       |
+|   _   ||       ||   |_| ||       ||   |  | ||   |   |   |  |   _   || ||_|| |
+|__| |__||_______||_______||_______||___|  |_||___|   |___|  |__| |__||_|   |_|
+
+This file contains the functions pertaining to how Shuttlecraft creates the "latest" feed
+
+**/
+
+import debug from 'debug';
+import { fetchUser } from './users.js';
+import { getNote, getLikes, getBoosts, isReplyToMyPost, isReplyToFollowing, isFollowing } from './account.js';
+import { getActivity } from './notes.js';
+import { INDEX } from './storage.js';
+import { ActivityPub } from './ActivityPub.js';
+
+const logger = debug('ono:algorithm');
+
+/**
+ * The function `sortByDate` takes two values and compares them. It is used to sort posts in reverse
+ * order.
+ * @param a - The first object being compared.
+ * @param b - The parameter `b` represents the second item being compared in the `sortByDate` function.
+ * @returns The `sortByDate` function returns -1 if `a.published` is greater than `b.published`, 1 if
+ * `a.published` is less than `b.published`, and 0 if `a.published` is equal to `b.published`.
+ */
+export const sortByDate = (a, b) => {
+  if (a.published > b.published) {
+    return -1;
+  } else if (a.published < b.published) {
+    return 1;
+  } else {
+    return 0;
+  }
+};
+
+/**
+ * Given an activity record OR an id for an activity record, returns the full activity along with
+ * the actor, and, if a boost, information about the boost and boosting user
+ * @param {*} activityOrId
+ * @returns {note, actor, boost, booster}
+ */
+export const getFullPostDetails = async activityOrId => {
+  const likes = await getLikes();
+  const boosts = await getBoosts();
+
+  let note, actor, boost, booster;
+  try {
+    if (typeof activityOrId === 'string') {
+      note = await getActivity(activityOrId);
+    } else {
+      note = activityOrId;
+    }
+  } catch (err) {
+    console.error(err);
+    console.error('Could not load post in feed');
+    return;
+  }
+
+  const account = await fetchUser(note.attributedTo || note.actor);
+  actor = account.actor;
+
+  if (note.type === 'Announce') {
+    boost = note;
+    booster = actor;
+    try {
+      note = await getActivity(boost.object);
+      const op = await fetchUser(note.attributedTo);
+      actor = op.actor;
+    } catch (err) {
+      console.error(err);
+      console.error('Could not fetch boosted post...', boost.object);
+      return;
+    }
+  }
+
+  note.isLiked = !!likes.some(l => l.activityId === note.id);
+  note.isBoosted = !!boosts.some(l => l.activityId === note.id);
+
+  return {
+    note,
+    actor,
+    boost,
+
+    booster
+  };
+};
+
+/**
+ * The `getActivityStream` function generates an activity stream by sorting and filtering posts, and
+ * then iterating over them to retrieve the necessary details.
+ * @param limit - The `limit` parameter specifies the maximum number of posts to include in the
+ * activity stream. It determines how many posts will be returned in the `activitystream` array.
+ * @param offset - The `offset` parameter is used to determine the starting point of the activity
+ * stream. It specifies the index position in the `sortedSlice` array from where the iteration should
+ * begin.
+ * @returns an object with two properties: "activitystream" and "next". The "activitystream" property
+ * contains an array of posts, and the "next" property contains the index of the next post to be
+ * fetched.
+ */
+export const getActivityStream = async (limit, offset) => {
+  logger('Generating activity stream...');
+
+  // sort all known posts by date quickly
+  // exclude any posts that are marked as unreachable
+  // and also exclude posts without a published date
+  const sortedSlice = INDEX.filter(p => p.type !== 'fail' && !isNaN(p.published)).sort(sortByDate);
+
+  // res will contain the
+  const stream = [];
+
+  // iterate over the list until we get enough posts (or run out of posts)
+  let postIndex;
+  for (postIndex = offset; postIndex < sortedSlice.length; postIndex++) {
+    const postObject = sortedSlice[postIndex];
+
+    // process a post by someone else
+    if (postObject.type === 'activity') {
+      // Ignore posts from people I am not following
+      if (!isFollowing(postObject.actor)) {
+        continue;
+      }
+
+      if (!postObject.inReplyTo || isReplyToMyPost(postObject) || (await isReplyToFollowing(postObject))) {
+        try {
+          const post = await getFullPostDetails(postObject.id);
+          stream.push(post);
+        } catch (err) {
+          console.error('error while loading post from index');
+        }
+      } else {
+        // disgard replies i don't care about
+      }
+    }
+
+    // process a post by me
+    if (postObject.type === 'note') {
+      const post = await getFullPostDetails(postObject.id);
+      stream.push(post);
+    }
+
+    // if we have enough posts, break out of the loop
+    if (stream.length === limit) {
+      break;
+    }
+  }
+
+  return {
+    activitystream: stream,
+    next: postIndex
+  };
+};
+
+/**
+ * The function `getActivitySince` retrieves activity data since a specified date, excluding the user's
+ * own activity if specified.
+ * @param since - The `since` parameter is a timestamp indicating the starting point from which you
+ * want to retrieve activity. Only activities that occurred after this timestamp will be included in
+ * the result.
+ * @param [excludeSelf=false] - The `excludeSelf` parameter is a boolean flag that determines whether
+ * or not to exclude the posts made by the current user (self) from the result. If `excludeSelf` is set
+ * to `true`, the posts made by the current user will be filtered out from the result. If `exclude
+ * @returns an object with a property called "activitystream" which contains an array of objects. Each
+ * object in the array represents an activity or a note. Each object has two properties: "note" which
+ * represents the content of the activity or note, and "actor" which represents the actor who performed
+ * the activity or created the note.
+ */
+export const getActivitySince = async (since, excludeSelf = false) => {
+  // sort all known posts by date quickly
+  const sortedSlice = INDEX.filter(p => p.type !== 'fail' && !isNaN(p.published))
+    .sort(sortByDate)
+    .filter(p => {
+      if (excludeSelf && p.actor === ActivityPub.actor.id) {
+        return false;
+      }
+      return p.published > since;
+    });
+
+  const stream = [];
+  let postIndex;
+  for (postIndex = 0; postIndex < sortedSlice.length; postIndex++) {
+    const postObject = sortedSlice[postIndex];
+    if (postObject.type === 'activity') {
+      if (isFollowing(postObject.actor)) {
+        if (!postObject.inReplyTo || isReplyToMyPost(postObject) || (await isReplyToFollowing(postObject))) {
+          try {
+            const { actor } = await fetchUser(postObject.actor);
+            const post = await getActivity(postObject.id);
+            stream.push({
+              note: post,
+              actor
+            });
+          } catch (err) {
+            console.error('error while loading post from index');
+          }
+        } else {
+          // disgard replies i don't care about
+        }
+      } else {
+        // disregard not from following
+      }
+    } else {
+      const post = await getNote(postObject.id);
+      stream.push({
+        note: post,
+        actor: ActivityPub.actor
+      });
+    }
+  }
+
+  return {
+    activitystream: stream
+  };
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.2 on Thu Dec 14 2023 18:11:22 GMT-0800 (Pacific Standard Time) +
+ + + + + diff --git a/docs/users.js.html b/docs/users.js.html new file mode 100644 index 00000000..45001cb7 --- /dev/null +++ b/docs/users.js.html @@ -0,0 +1,162 @@ + + + + + JSDoc: Source: users.js + + + + + + + + + + +
+ +

Source: users.js

+ + + + + + +
+
+
import path from 'path';
+import fs from 'fs';
+import debug from 'debug';
+import { readJSONDictionary, writeJSONDictionary, pathToUsers } from './storage.js';
+import { ActivityPub } from './ActivityPub.js';
+
+const logger = debug('ono:users');
+
+/**
+ * The function `fetchUserFromSource` fetches user information from a given webId or username using the
+ * ActivityPub protocol.
+ * @param username - The `username` parameter is the username of the user you want to fetch from the
+ * source. It is used to identify the user and retrieve their information.
+ * @param webId - The `webId` parameter is a string that represents the unique identifier of a user on
+ * the web. It is used to fetch the actor information of the user from an ActivityPub server. If the
+ * `webId` parameter is not provided, the function will attempt to fetch the actor information using
+ * the
+ * @returns The function `fetchUserFromSource` returns an object with the properties `webfinger`,
+ * `actor`, and `lastFetched`.
+ */
+const fetchUserFromSource = async (username, webId) => {
+  let webfinger;
+
+  if (!webId) {
+    try {
+      webfinger = await ActivityPub.webfinger(username);
+    } catch (err) {
+      return {
+        actor: {
+          name: username,
+          preferredUsername: username
+        }
+      };
+    }
+  }
+
+  // now fetch actor info
+  const self = webId || webfinger.links.filter(l => l.rel === 'self')[0]?.href;
+  let actor;
+  if (self) {
+    logger(`fetch activitypub.actor ${self}`);
+    try {
+      actor = await ActivityPub.fetchActor(self);
+    } catch (err) {
+      return {
+        actor: {
+          name: username,
+          preferredUsername: username,
+          id: webId
+        }
+      };
+    }
+  } else {
+    throw new Error('could not find self link in webfinger');
+  }
+
+  const userFile = path.resolve(pathToUsers, `${username}.json`);
+  logger(`update ${userFile}`);
+  writeJSONDictionary(userFile, {
+    webfinger,
+    actor,
+    lastFetched: new Date().getTime()
+  });
+
+  return {
+    webfinger,
+    actor,
+    lastFetched: new Date().getTime()
+  };
+};
+
+/**
+ * The `fetchUser` function fetches user information either from a cache or from a source, with an
+ * option to skip fingerprinting if the user is already an ActivityPub URL.
+ * @returns The function `fetchUser` returns a Promise that resolves to the user account information.
+ */
+export const fetchUser = async user => {
+  let skipFinger = false;
+  const now = new Date().getTime();
+  const cacheMax = 1 * 60 * 60 * 1000; // cache user info for 1 hour
+
+  const username = ActivityPub.getUsername(user);
+  // if we start with an activitypub url, we don't need to finger to get it
+  if (user.startsWith('https://')) {
+    skipFinger = true;
+  }
+
+  const userFile = path.resolve(pathToUsers, `${username}.json`);
+  logger('load user', user, userFile);
+
+  if (fs.existsSync(userFile)) {
+    const account = readJSONDictionary(userFile);
+    // check date to see if we need to refetch...
+    if (account.lastFetched && account.lastFetched > now - cacheMax) {
+      return account;
+    } else if (!account.actor || !account.actor.id) {
+      // do nothing and fall through to the live fetch
+      // since we don't have a full user account here
+    } else {
+      logger('fetch fresh user for', user, `${username}`);
+      // attempt to fetch a new one async
+      // TODO: needs to be debounced - could try to load same user many times quickly
+      fetchUserFromSource(username, account?.actor?.id).catch(err =>
+        console.error('Error updating user data for', username, err)
+      );
+      return account;
+    }
+  }
+
+  return await fetchUserFromSource(username, skipFinger ? user : null);
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.2 on Thu Dec 14 2023 18:11:22 GMT-0800 (Pacific Standard Time) +
+ + + + + diff --git a/docs/webfinger.js.html b/docs/webfinger.js.html new file mode 100644 index 00000000..07104a6d --- /dev/null +++ b/docs/webfinger.js.html @@ -0,0 +1,100 @@ + + + + + JSDoc: Source: webfinger.js + + + + + + + + + + +
+ +

Source: webfinger.js

+ + + + + + +
+
+
import express from 'express';
+
+/**
+ * Express.js router for handling webfinger-related routes.
+ *
+ * @typedef {Object} WebfingerRouter
+ * @property {Function} getResource - Route handler for retrieving a webfinger resource.
+ *
+ * @example
+ * // Example usage:
+ * import { router as webfingerRouter } from './webfingerRouter';
+ * app.use('/webfinger', webfingerRouter);
+ */
+export const router = express.Router();
+
+/**
+ * Route handler for retrieving a webfinger resource.
+ *
+ * @function
+ * @param {Object} req - Express.js request object.
+ * @param {Object} res - Express.js response object.
+ * @returns {void} Responds with a webfinger resource or an error message based on the request.
+ *
+ * @throws {Error} Responds with a 400 Bad Request if the 'resource' query parameter is missing or incorrectly formatted.
+ * @throws {Error} Responds with a 404 Not Found if no record is found for the provided 'resource'.
+ *
+ */
+router.get('/', function (req, res) {
+  // Extract the 'resource' query parameter from the request
+  const resource = req.query.resource;
+
+  // Check if the 'resource' parameter is missing or incorrectly formatted
+  if (!resource || !resource.includes('acct:')) {
+    return res
+      .status(400)
+      .send(
+        'Bad request. Please make sure "acct:USER@DOMAIN" is what you are sending as the "resource" query parameter.'
+      );
+  } else {
+    // Check if the provided 'resource' matches the stored webfinger subject
+    if (resource === req.app.get('account').webfinger.subject) {
+      // Respond with the webfinger resource in JSON format
+      res.json(req.app.get('account').webfinger);
+    } else {
+      // Respond with a 404 Not Found if no record is found for the provided 'resource'
+      return res.status(404).send(`No record found for ${resource}.`);
+    }
+  }
+});
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.2 on Thu Dec 14 2023 18:13:17 GMT-0800 (Pacific Standard Time) +
+ + + + + diff --git a/index.js b/index.js index 86a93115..d8d32a02 100644 --- a/index.js +++ b/index.js @@ -1,52 +1,188 @@ -import express from 'express'; -import { create } from 'express-handlebars'; +// index.js is the start point for our project + +// middleware to parse request bodies in different formats (e.g., JSON) +import bodyParser from 'body-parser'; + +// middleware to parse cookies in incoming requests import cookieParser from 'cookie-parser'; +// Cross-Origin Resource Sharing (CORS) middleware for enabling cross-origin requests +import cors from 'cors'; + +// the dotenv module for loading environment variables from a .env file import dotenv from 'dotenv'; -import bodyParser from 'body-parser'; -import cors from 'cors'; +// the Express.js framework for building web applications +import express from 'express'; + +// the Handlebars view engine for rendering dynamic HTML content +import { create } from 'express-handlebars'; + +// the built-in Node.js HTTP module for creating an HTTP server import http from 'http'; -import basicAuth from 'express-basic-auth'; + +// the Moment.js library for handling dates and times import moment from 'moment'; + +// ActivityPub for handling ActivityPub requests import { ActivityPub } from './lib/ActivityPub.js'; -import { ensureAccount } from './lib/account.js'; -import { account, webfinger, inbox, outbox, admin, notes, publicFacing } from './routes/index.js'; + +// Check if account already exists +import { ifAccount } from './lib/account.js'; + +// Authentication middleware +import { handleAuthenticatedUser } from './lib/authentication.js'; + +import { + UserProfileRouter, + WebfingerRouter, + inbox, + outbox, + admin, + notes, + publicFacing, + accountHandler +} from './routes/index.js'; // load process.env from .env file dotenv.config(); -const { USERNAME, PASS, DOMAIN, PORT } = process.env; -['USERNAME', 'PASS', 'DOMAIN'].forEach(required => { - if (!process.env[required]) { - console.error(`Missing required environment variable: \`${required}\`. Exiting.`); - process.exit(1); - } -}); +const DOMAIN = process.env.DOMAIN; +const PORT = process.env.PORT; +// const envVariables = ['USER_NAME', 'PASS', 'DOMAIN']; +const envVariables = ['DOMAIN']; const PATH_TO_TEMPLATES = './design'; -const app = express(); + +/** + * Check the existence of required environment variables. + * + * @param {string[]} env_variables - An array of environment variable names that are required. + * @throws {Error} Throws an error and exits the process if any required environment variable is missing. + */ +function checkRequiredEnvironmentVariables(envVariables) { + envVariables.forEach(reqdVariable => { + /** + * Check if the required environment variable is missing. + * If missing, log an error message and exit the process. + * + * @example + * // Example usage: + * checkRequiredEnvironmentVariables(['PORT', 'DATABASE_URL']); + */ + if (!process.env[reqdVariable]) { + console.error(`Missing required environment variable: \`${reqdVariable}\`. Exiting.`); + process.exit(1); + } + }); +} +checkRequiredEnvironmentVariables(envVariables); + +export const app = express(); +// Export app +// module.exports = app; +/** + * Handlebars helper functions for custom template rendering. + * + * @typedef {Object} HandlebarsHelpers + * @property {Function} isVideo - Check if a string contains 'video' and execute the provided block if true. + * @property {Function} isImage - Check if a string contains 'image' and execute the provided block if true. + * @property {Function} isEq - Check if two values are equal and execute the provided block if true. + * @property {Function} or - Logical OR between two values. + * @property {Function} timesince - Format a date to show the time elapsed since the specified date. + * @property {Function} getUsername - Get the username using the ActivityPub module. + * @property {Function} stripProtocol - Remove 'https://' from the beginning of a string. + * @property {Function} stripHTML - Remove HTML tags from a string. + */ + +/** + * Create an instance of Handlebars with custom helpers. + * + * @type {Handlebars} + * @see {@link https://handlebarsjs.com/api-reference/helpers.html} + */ const hbs = create({ helpers: { + /** + * Check if a string contains 'video' and execute the provided block if true. + * @function + * @param {string} str - The string to check. + * @param {Object} options - Handlebars options object. + * @returns {string} - The rendered block if the condition is true. + */ isVideo: (str, options) => { if (str && str.includes('video')) return options.fn(this); }, + + /** + * Check if a string contains 'image' and execute the provided block if true. + * @function + * @param {string} str - The string to check. + * @param {Object} options - Handlebars options object. + * @returns {string} - The rendered block if the condition is true. + */ isImage: (str, options) => { if (str && str.includes('image')) return options.fn(this); }, + + /** + * Check if two values are equal and execute the provided block if true. + * @function + * @param {*} a - The first value. + * @param {*} b - The second value. + * @param {Object} options - Handlebars options object. + * @returns {string} - The rendered block if the condition is true. + */ isEq: (a, b, options) => { // eslint-disable-next-line if (a == b) return options.fn(this); }, + + /** + * Logical OR between two values. + * @function + * @param {*} a - The first value. + * @param {*} b - The second value. + * @param {Object} options - Handlebars options object. + * @returns {*} - The result of the logical OR operation. + */ or: (a, b, options) => { return a || b; }, + + /** + * Format a date to show the time elapsed since the specified date. + * @function + * @param {Date} date - The date to be formatted. + * @returns {string} - The formatted time elapsed string. + */ timesince: date => { return moment(date).fromNow(); }, + + /** + * Get the username using the ActivityPub module. + * @function + * @param {*} user - The user object. + * @returns {string} - The username. + */ getUsername: user => { return ActivityPub.getUsername(user); }, + + /** + * Remove 'https://' from the beginning of a string. + * @function + * @param {string} str - The string to process. + * @returns {string} - The string with 'https://' removed. + */ stripProtocol: str => str.replace(/^https:\/\//, ''), + + /** + * Remove HTML tags from a string. + * @function + * @param {string} str - The string containing HTML tags. + * @returns {string} - The string with HTML tags removed. + */ stripHTML: str => str .replace(/<\/p>/, '\n') @@ -55,100 +191,90 @@ const hbs = create({ } }); -app.set('domain', DOMAIN); -app.set('port', process.env.PORT || PORT || 3000); -app.set('port-https', process.env.PORT_HTTPS || 8443); -app.engine('handlebars', hbs.engine); -app.set('views', PATH_TO_TEMPLATES); -app.set('view engine', 'handlebars'); -app.use( - bodyParser.json({ - type: 'application/activity+json' - }) -); // support json encoded bodies -app.use( - bodyParser.json({ - type: 'application/json' - }) -); // support json encoded bodies -app.use( - bodyParser.json({ - type: 'application/ld+json' - }) -); // support json encoded bodies +const setExpressApp = app => { + app.set('domain', DOMAIN); + app.set('port', process.env.PORT || PORT || 3000); + app.set('port-https', process.env.PORT_HTTPS || 8443); + app.engine('handlebars', hbs.engine); + app.set('views', PATH_TO_TEMPLATES); + app.set('view engine', 'handlebars'); + app.use( + bodyParser.json({ + type: 'application/activity+json' + }) + ); // support json encoded bodies + app.use( + bodyParser.json({ + type: 'application/json' + }) + ); // support json encoded bodies + app.use( + bodyParser.json({ + type: 'application/ld+json' + }) + ); // support json encoded bodies -app.use(cookieParser()); + app.use(cookieParser()); -app.use( - bodyParser.urlencoded({ - extended: true - }) -); // support encoded bodies - -// basic http authorizer -const basicUserAuth = basicAuth({ - authorizer: asyncAuthorizer, - authorizeAsync: true, - challenge: true -}); + app.use( + bodyParser.urlencoded({ + extended: true + }) + ); // support encoded bodies +}; -function asyncAuthorizer(username, password, cb) { - let isAuthorized = false; - const isPasswordAuthorized = username === USERNAME; - const isUsernameAuthorized = password === PASS; - isAuthorized = isPasswordAuthorized && isUsernameAuthorized; - if (isAuthorized) { - return cb(null, true); +setExpressApp(app); + +const authWrapper = (req, res, next) => { + if (ifAccount()) { + handleAuthenticatedUser(req, res, next); } else { - return cb(null, false); + res.redirect('/account/create'); } -} +}; -// Load/create account file -ensureAccount(USERNAME, DOMAIN).then(myaccount => { - const authWrapper = (req, res, next) => { - if (req.cookies.token) { - if (req.cookies.token === myaccount.apikey) { - return next(); - } - } - return basicUserAuth(req, res, next); - }; +console.log(`ACCESS DASHBOARD: https://${DOMAIN}/private`); - // set the server to use the main account as its primary actor - ActivityPub.account = myaccount; - console.log(`BOOTING SERVER FOR ACCOUNT: ${myaccount.actor.preferredUsername}`); - console.log(`ACCESS DASHBOARD: https://${DOMAIN}/private`); +// set up globals +app.set('domain', DOMAIN); +// app.set('account', myaccount); - // set up globals - app.set('domain', DOMAIN); - app.set('account', myaccount); +// serve webfinger response +app.use('/.well-known/webfinger', cors(), WebfingerRouter); +// server user profile and follower list +app.use('/u', cors(), UserProfileRouter); - // serve webfinger response - app.use('/.well-known/webfinger', cors(), webfinger); - // server user profile and follower list - app.use('/u', cors(), account); +// serve individual posts +app.use('/m', cors(), notes); - // serve individual posts - app.use('/m', cors(), notes); +// handle incoming requests +app.use('/api/inbox', cors(), inbox); +app.use('/api/outbox', cors(), outbox); - // handle incoming requests - app.use('/api/inbox', cors(), inbox); - app.use('/api/outbox', cors(), outbox); +// serve account creation and login +app.use( + '/account', + cors({ + credentials: true, + origin: true + }), + accountHandler +); - app.use( - '/private', - cors({ - credentials: true, - origin: true - }), - authWrapper, - admin - ); - app.use('/', cors(), publicFacing); - app.use('/', express.static('public/')); - - http.createServer(app).listen(app.get('port'), function () { - console.log('Express server listening on port ' + app.get('port')); - }); +// serve user dashboard +app.use( + '/private', + cors({ + credentials: true, + origin: true + }), + authWrapper, + admin +); + +app.use('/', cors(), publicFacing); +app.use('/', express.static('public/')); + +http.createServer(app).listen(app.get('port'), function () { + console.log('Express server listening on port ' + app.get('port')); }); diff --git a/jest.config.cjs b/jest.config.cjs new file mode 100644 index 00000000..5e4ffd79 --- /dev/null +++ b/jest.config.cjs @@ -0,0 +1,7 @@ +module.exports = { + fakeTimers: { + enableGlobally: true, + }, + setupFiles: ["/.jest/setEnvVars.js"], + transformIgnorePatterns: [], +} \ No newline at end of file diff --git a/lib/ActivityPub.js b/lib/ActivityPub.js index 333f6a24..dcd8519b 100644 --- a/lib/ActivityPub.js +++ b/lib/ActivityPub.js @@ -6,8 +6,14 @@ const logger = debug('ActivityPub'); /** * ActivityPubClient - a class for sending and fetching ActivityPub content + * @class */ export class ActivityPubClient { + /** + * Constructor for ActivityPubClient + * @constructor + * @param {Object} account - The user account. + */ constructor(account) { logger('Initializing ActivityPub client for user:', account); if (account) { @@ -15,24 +21,47 @@ export class ActivityPubClient { } } + /** + * Setter for actor property + * @param {Object} actor - The actor object. + */ set actor(actor) { this._actor = actor; } + /** + * Getter for actor property + * @returns {Object} The actor object. + */ get actor() { return this._actor; } + /** + * Setter for account property + * @param {Object} account - The user account. + */ set account(account) { logger('Setting account:', account); this._account = account; this._actor = account?.actor; } + /** + * Getter for account property + * @returns {Object} The user account. + */ get account() { return this._account; } + /** + * Fetches the Webfinger data for a given username + * @async + * @param {string} username - The username to fetch Webfinger data for. + * @returns {Promise} The Webfinger data. + * @throws {Error} If Webfinger fetch fails. + */ async webfinger(username) { const { targetDomain } = this.getUsernameDomain(username); @@ -52,13 +81,19 @@ export class ActivityPubClient { } } + /** + * Fetches the actor data for a given user ID + * @async + * @param {string} userId - The user ID to fetch actor data for. + * @returns {Promise} The actor data. + * @throws {Error} If actor fetch fails. + */ async fetchActor(userId) { const actorQuery = await ActivityPub.fetch(userId, {}); if (actorQuery.ok) { const actor = await actorQuery.json(); return actor; } else { - // logger('failed to load actor', actorQuery.status, actorQuery.statusText, await actorQuery.text()); throw new Error('failed to load actor'); } } @@ -76,21 +111,22 @@ export class ActivityPubClient { const urlFragment = url.pathname + (url.searchParams.toString() ? `?${url.searchParams.toString()}` : ''); const signer = crypto.createSign('sha256'); - const d = new Date(); - const stringToSign = `(request-target): get ${urlFragment}\nhost: ${url.hostname}\ndate: ${d.toUTCString()}`; + const date = new Date(); + const stringToSign = `(request-target): get ${urlFragment}\nhost: ${url.hostname}\ndate: ${date.toUTCString()}`; signer.update(stringToSign); signer.end(); const signature = signer.sign(this.account.privateKey); const signatureB64 = signature.toString('base64'); const header = `keyId="${this.actor.publicKey.id}",headers="(request-target) host date",signature="${signatureB64}"`; options.headers = { - Date: d.toUTCString(), + Date: date.toUTCString(), Host: url.hostname, Accept: 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"', Signature: header }; const controller = new AbortController(); + // set timeout for 5s setTimeout(() => controller.abort(), 5000); options.signal = controller.signal; @@ -118,10 +154,10 @@ export class ActivityPubClient { const digestHash = crypto.createHash('sha256').update(JSON.stringify(message)).digest('base64'); const signer = crypto.createSign('sha256'); - const d = new Date(); + const date = new Date(); const stringToSign = `(request-target): post ${inboxFragment}\nhost: ${ url.hostname - }\ndate: ${d.toUTCString()}\ndigest: SHA-256=${digestHash}`; + }\ndate: ${date.toUTCString()}\ndigest: SHA-256=${digestHash}`; signer.update(stringToSign); signer.end(); const signature = signer.sign(this.account.privateKey); @@ -139,7 +175,7 @@ export class ActivityPubClient { headers: { Host: url.hostname, 'Content-type': 'application/activity+json', - Date: d.toUTCString(), + Date: date.toUTCString(), Digest: `SHA-256=${digestHash}`, Signature: header }, @@ -402,7 +438,11 @@ export class ActivityPubClient { } getUsernameDomain(userIdorName) { - let targetDomain, username; + let targetDomain = ''; + let username = ''; + if (!userIdorName) { + return { username, targetDomain }; + } if (userIdorName.startsWith('https://')) { const actor = new URL(userIdorName); targetDomain = actor.hostname; diff --git a/lib/Markdown.js b/lib/Markdown.js index 1a8876e3..bf500d3e 100644 --- a/lib/Markdown.js +++ b/lib/Markdown.js @@ -1,6 +1,6 @@ /* This module contains the markdown renderer used to format posts - By default, urls will be linkified with nofollow noopener and noreferrer attributes + By default, urls will be linkifies with nofollow, noopener, and noreferrer attributes Override those attributes by setting LINK_ATTRIBUTES in the .env file Usage: @@ -10,6 +10,7 @@ const html = md.render(markdown); import dotenv from 'dotenv'; import MarkdownIt from 'markdown-it'; + dotenv.config(); const md = new MarkdownIt({ @@ -19,10 +20,30 @@ const md = new MarkdownIt({ const LINK_ATTRIBUTES = process.env.LINK_ATTRIBUTES || 'nofollow noopener noreferrer'; -// customize the link formatter to include noopener noreferrer links -// this prevents browsers from telling downstream pages about where the links came from -// and protects the privacy of our users. -// code from: https://publishing-project.rivendellweb.net/customizing-markdown-it/ +/** + * The above function modifies the rendering of link tags in Markdown by adding a "rel" attribute with + * the value of LINK_ATTRIBUTES. + * @param tokens - The `tokens` parameter is an array of token objects. Each token object represents a + * part of the Markdown document, such as a paragraph, heading, link, etc. The `tokens` array is passed + * to the renderer function to generate the corresponding HTML output. + * @param idx - The `idx` parameter in the code refers to the index of the current token being rendered + * in the array of tokens. + * @param options - The `options` parameter is an object that contains various options and + * configurations for the Markdown renderer. It can include settings such as the rendering mode, the + * HTML tag names to use for different elements, and other customization options. + * @param env - The `env` parameter in the code snippet refers to the environment object. It is an + * optional parameter that can be used to pass additional information or configuration to the rendering + * rules. It can be used to store and access data that needs to be shared between different rendering + * rules. + * @param self - The `self` parameter refers to the Markdown-it instance. It is used to access the + * `renderToken` method and the `renderer` object, which contains the rules for rendering Markdown + * tokens. + * + * customize the link formatter to include noopener noreferrer links + * this prevents browsers from telling downstream pages about where the links came from + * and protects the privacy of our users. + * code from: https://publishing-project.rivendellweb.net/customizing-markdown-it/ + */ const proxy = (tokens, idx, options, env, self) => self.renderToken(tokens, idx, options); const defaultLinkOpenRenderer = md.renderer.rules.link_open || proxy; md.renderer.rules.link_open = function (tokens, idx, options, env, self) { diff --git a/lib/__tests__/ActivityPub.jest.js b/lib/__tests__/ActivityPub.jest.js new file mode 100644 index 00000000..b6793b37 --- /dev/null +++ b/lib/__tests__/ActivityPub.jest.js @@ -0,0 +1,366 @@ +import { ActivityPubClient, ActivityPub } from '../ActivityPub'; +import crypto from 'crypto'; + +jest.mock('node-fetch'); + +import fetch from 'node-fetch'; + +afterEach(() => { + jest.restoreAllMocks(); +}); + +describe('Tests for ActivityPubClient constructor', () => { + test('Check successful initialization of account', () => { + const expectedAccount = { actor: 'justin' }; + const activityPubClient = new ActivityPubClient(expectedAccount); + expect(activityPubClient.account).toStrictEqual(expectedAccount); + }); +}); + +describe('Tests for ActivityPubClient set and get actor', () => { + test('Check successful setting and getting of actor', () => { + const activityPubClient = new ActivityPubClient({ actor: 'justin' }); + expect(activityPubClient.actor).toBe('justin'); + activityPubClient.actor = 'jay'; + expect(activityPubClient.actor).toBe('jay'); + }); +}); + +describe('Tests for ActivityPubClient set and get account', () => { + test('Check successful setting and getting of account', () => { + const activityPubClient = new ActivityPubClient(); + expect(activityPubClient.account).toBe(undefined); + const expectedAccount = { actor: 'justin' }; + activityPubClient.account = expectedAccount; + expect(activityPubClient.account).toStrictEqual(expectedAccount); + expect(activityPubClient.actor).toBe('justin'); + }); +}); + +describe('Tests for ActivityPubClient webfinger', () => { + test('Check successful fetching webfinger', async () => { + fetch.mockReturnValue( + Promise.resolve({ + ok: true, + json: () => Promise.resolve({ testWebfinger: 'testWebfinger' }) + }) + ); + + const activityPubClient = new ActivityPubClient(); + const webfinger = await activityPubClient.webfinger('justin@shuttlecraft.com'); + expect(webfinger).toStrictEqual({ testWebfinger: 'testWebfinger' }); + }); + + test('Check error when fetching webfinger', async () => { + fetch.mockReturnValue( + Promise.resolve({ + ok: false, + json: () => Promise.resolve({ testWebfinger: 'testWebfinger' }) + }) + ); + + const activityPubClient = new ActivityPubClient(); + try { + await activityPubClient.webfinger('justin@shuttlecraft.com'); + } catch (e) { + expect(e).toMatchObject( + new Error( + 'could not get webfinger https://shuttlecraft.com/.well-known/webfinger?resource=acct:justin@shuttlecraft.com: undefined' + ) + ); + } + }); +}); + +describe('Tests for ActivityPubClient fetchActor', () => { + test('Check successful fetching actor', async () => { + fetch.mockReturnValue( + Promise.resolve({ + ok: true, + json: () => Promise.resolve({ testActor: 'testActor' }) + }) + ); + + const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', { + modulusLength: 2048, + publicKeyEncoding: { + type: 'pkcs1', + format: 'pem' + }, + privateKeyEncoding: { + type: 'pkcs1', + format: 'pem' + } + }); + + jest + .spyOn(ActivityPub, 'account', 'get') + .mockReturnValue({ actor: { publicKey: { id: publicKey } }, privateKey: privateKey }); + jest.spyOn(ActivityPub, 'actor', 'get').mockReturnValue({ publicKey: { id: publicKey } }); + + const actor = await ActivityPub.fetchActor('https://shuttlecraft.com/justin'); + expect(actor).toStrictEqual({ testActor: 'testActor' }); + }); + + test('Check error when fetching actor', async () => { + fetch.mockReturnValue( + Promise.resolve({ + ok: false, + json: () => Promise.resolve({ testActor: 'testActor' }) + }) + ); + + const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', { + modulusLength: 2048, + publicKeyEncoding: { + type: 'pkcs1', + format: 'pem' + }, + privateKeyEncoding: { + type: 'pkcs1', + format: 'pem' + } + }); + + jest + .spyOn(ActivityPub, 'account', 'get') + .mockReturnValue({ actor: { publicKey: { id: publicKey } }, privateKey: privateKey }); + jest.spyOn(ActivityPub, 'actor', 'get').mockReturnValue({ publicKey: { id: publicKey } }); + + try { + await ActivityPub.fetchActor('https://shuttlecraft.com/justin'); + } catch (e) { + expect(e).toMatchObject(new Error('failed to load actor')); + } + }); +}); + +describe('Tests for ActivityPubClient fetch', () => { + test('Check successful', async () => { + fetch.mockReturnValue( + Promise.resolve({ + fetch: 'fetch' + }) + ); + + const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', { + modulusLength: 2048, + publicKeyEncoding: { + type: 'pkcs1', + format: 'pem' + }, + privateKeyEncoding: { + type: 'pkcs1', + format: 'pem' + } + }); + + const activityPubClient = new ActivityPubClient({ + actor: { publicKey: { id: publicKey } }, + privateKey: privateKey + }); + const fetchResult = await activityPubClient.fetch('https://shuttlecraft.com/justin', {}); + expect(fetchResult).toStrictEqual({ fetch: 'fetch' }); + }); +}); + +describe('Tests for ActivityPubClient sendLike', () => { + test('Check successful', async () => { + const activityPubClient = new ActivityPubClient({ actor: { id: 'justin' } }); + const post = { id: 'post' }; + const recipient = { inbox: 'justin@shuttlecraft.com' }; + + const sendLikeResult = await activityPubClient.sendLike(post, recipient); + expect(sendLikeResult['@context']).toBe('https://www.w3.org/ns/activitystreams'); + expect(sendLikeResult.type).toBe('Like'); + expect(sendLikeResult.actor).toBe('justin'); + expect(sendLikeResult.object).toBe('post'); + }); +}); + +describe('Tests for ActivityPubClient sendUndoLike', () => { + test('Check successful', async () => { + const activityPubClient = new ActivityPubClient({ actor: { id: 'justin' } }); + const post = { id: 'post' }; + const recipient = { inbox: 'justin@shuttlecraft.com' }; + + const sendUndoLikeResult = await activityPubClient.sendUndoLike(post, recipient, 'originalId'); + expect(sendUndoLikeResult['@context']).toBe('https://www.w3.org/ns/activitystreams'); + expect(sendUndoLikeResult.id).toBe('originalId/undo'); + expect(sendUndoLikeResult.type).toBe('Undo'); + expect(sendUndoLikeResult.actor).toBe('justin'); + expect(sendUndoLikeResult.object).toStrictEqual({ + id: 'originalId', + type: 'Like', + actor: 'justin', + object: 'post' + }); + }); +}); + +describe('Tests for ActivityPubClient sendFollow', () => { + test('Check successful', async () => { + const activityPubClient = new ActivityPubClient({ actor: { id: 'justin' } }); + const recipient = { inbox: 'justin@shuttlecraft.com', id: 'justin' }; + + const sendFollowResult = await activityPubClient.sendFollow(recipient); + expect(sendFollowResult['@context']).toBe('https://www.w3.org/ns/activitystreams'); + expect(sendFollowResult.type).toBe('Follow'); + expect(sendFollowResult.actor).toBe('justin'); + expect(sendFollowResult.object).toBe('justin'); + }); +}); + +describe('Tests for ActivityPubClient sendUndoFollow', () => { + test('Check successful', async () => { + const activityPubClient = new ActivityPubClient({ actor: { id: 'justin' } }); + const recipient = { inbox: 'justin@shuttlecraft.com', id: 'justin' }; + + const sendUndoFollowResult = await activityPubClient.sendUndoFollow(recipient, 'originalId'); + expect(sendUndoFollowResult['@context']).toBe('https://www.w3.org/ns/activitystreams'); + expect(sendUndoFollowResult.type).toBe('Undo'); + expect(sendUndoFollowResult.actor).toBe('justin'); + expect(sendUndoFollowResult.object).toStrictEqual({ + id: 'originalId', + type: 'Follow', + actor: 'justin', + object: 'justin' + }); + }); +}); + +describe('Tests for ActivityPubClient sendAccept', () => { + test('Check successful', async () => { + const activityPubClient = new ActivityPubClient({ actor: { id: 'justin' } }); + const recipient = { inbox: 'justin@shuttlecraft.com', id: 'justin' }; + const followRequest = { from: 'jay' }; + + const sendAcceptResult = await activityPubClient.sendAccept(recipient, followRequest); + expect(sendAcceptResult['@context']).toBe('https://www.w3.org/ns/activitystreams'); + expect(sendAcceptResult.type).toBe('Accept'); + expect(sendAcceptResult.actor).toBe('justin'); + expect(sendAcceptResult.object).toStrictEqual(followRequest); + }); +}); + +describe('Tests for ActivityPubClient sendUpdate', () => { + test('Check successful', async () => { + const activityPubClient = new ActivityPubClient({ actor: { id: 'justin' } }); + const recipient = { inbox: 'justin@shuttlecraft.com', id: 'justin' }; + const object = { id: 'updateOne', published: true, to: 'jay', cc: ['aditya'] }; + + const sendUpdateResult = await activityPubClient.sendUpdate(recipient, object); + expect(sendUpdateResult['@context']).toBe('https://www.w3.org/ns/activitystreams'); + expect(sendUpdateResult.id).toBe('updateOne/activity'); + expect(sendUpdateResult.published).toBe(true); + expect(sendUpdateResult.type).toBe('Update'); + expect(sendUpdateResult.actor).toBe('justin'); + expect(sendUpdateResult.object).toStrictEqual(object); + expect(sendUpdateResult.to).toBe('jay'); + expect(sendUpdateResult.cc).toStrictEqual(['aditya']); + }); +}); + +describe('Tests for ActivityPubClient sendCreate', () => { + test('Check successful', async () => { + const activityPubClient = new ActivityPubClient({ actor: { id: 'justin' } }); + const recipient = { inbox: 'justin@shuttlecraft.com', id: 'justin' }; + const object = { id: 'createOne', published: true, to: 'jay', cc: ['aditya'] }; + + const sendCreateResult = await activityPubClient.sendCreate(recipient, object); + expect(sendCreateResult['@context']).toBe('https://www.w3.org/ns/activitystreams'); + expect(sendCreateResult.id).toBe('createOne/activity'); + expect(sendCreateResult.published).toBe(true); + expect(sendCreateResult.type).toBe('Create'); + expect(sendCreateResult.actor).toBe('justin'); + expect(sendCreateResult.object).toStrictEqual(object); + expect(sendCreateResult.to).toBe('jay'); + expect(sendCreateResult.cc).toStrictEqual(['aditya']); + }); +}); + +describe('Tests for ActivityPubClient sendBoost', () => { + test('Check successful', async () => { + const mockDate = new Date('2023-01-01T00:00:00Z'); + jest.spyOn(global, 'Date').mockImplementation(() => mockDate); + + const activityPubClient = new ActivityPubClient({ actor: { id: 'justin', followers: ['jay', 'aditya'] } }); + const primaryRecipient = { inbox: 'justin@shuttlecraft.com', id: 'justin' }; + const post = { id: 'post' }; + const followers = ['jay', 'aditya']; + + const sendBoostResult = await activityPubClient.sendBoost(primaryRecipient, post, followers); + expect(sendBoostResult['@context']).toBe('https://www.w3.org/ns/activitystreams'); + expect(sendBoostResult.type).toBe('Announce'); + expect(sendBoostResult.actor).toBe('justin'); + expect(sendBoostResult.published).toBe('2023-01-01T00:00:00.000Z'); + expect(sendBoostResult.object).toBe('post'); + expect(sendBoostResult.to).toStrictEqual(['https://www.w3.org/ns/activitystreams#Public']); + expect(sendBoostResult.cc).toStrictEqual([['jay', 'aditya'], 'justin']); + }); +}); + +describe('Tests for ActivityPubClient sendUndoBoost', () => { + test('Check successful', async () => { + const activityPubClient = new ActivityPubClient({ actor: { id: 'justin', followers: ['jay', 'aditya'] } }); + const primaryRecipient = { inbox: 'justin@shuttlecraft.com', id: 'justin' }; + const post = { id: 'post', attributedTo: 'justin' }; + const followers = ['jay', 'aditya']; + + const sendUndoBoostResult = await activityPubClient.sendUndoBoost( + primaryRecipient, + post, + followers, + 'originalActivityId' + ); + expect(sendUndoBoostResult['@context']).toBe('https://www.w3.org/ns/activitystreams'); + expect(sendUndoBoostResult.id).toBe('originalActivityId/undo'); + expect(sendUndoBoostResult.type).toBe('Undo'); + expect(sendUndoBoostResult.actor).toBe('justin'); + expect(sendUndoBoostResult.object).toStrictEqual({ + id: 'originalActivityId', + type: 'Announce', + actor: 'justin', + object: 'post' + }); + expect(sendUndoBoostResult.to).toStrictEqual(['https://www.w3.org/ns/activitystreams#Public']); + expect(sendUndoBoostResult.cc).toStrictEqual([['jay', 'aditya'], 'justin']); + }); +}); + +describe('Tests for ActivityPubClient fetchOutbox', () => { + test('Check actor outbox is false', async () => { + const activityPubClient = new ActivityPubClient(); + + const fetchOutboxResult = await activityPubClient.fetchOutbox({ outbox: false }); + expect(fetchOutboxResult).toStrictEqual([]); + }); +}); + +describe('Tests for ActivityPubClient getUsernameDomain', () => { + test('Check when userIdorName is not passed as an argument', () => { + const activityPubClient = new ActivityPubClient(); + expect(activityPubClient.getUsernameDomain()).toStrictEqual({ username: '', targetDomain: '' }); + }); + + test('Check when userIdorName starts with https://', () => { + const activityPubClient = new ActivityPubClient(); + const expectedUsernameDomain = { username: 'justin', targetDomain: 'shuttlecraft.com' }; + expect(activityPubClient.getUsernameDomain('https://shuttlecraft.com/justin')).toStrictEqual( + expectedUsernameDomain + ); + }); + + test('Check when userIdorName starts without https://', () => { + const activityPubClient = new ActivityPubClient(); + const expectedUsernameDomain = { username: 'justin', targetDomain: 'shuttlecraft.com' }; + expect(activityPubClient.getUsernameDomain('justin@shuttlecraft.com')).toStrictEqual(expectedUsernameDomain); + }); +}); + +describe('Tests for ActivityPubClient getUsername', () => { + test('Check getting username successfully', () => { + const activityPubClient = new ActivityPubClient(); + expect(activityPubClient.getUsername('https://shuttlecraft.com/justin')).toStrictEqual('justin@shuttlecraft.com'); + }); +}); diff --git a/lib/__tests__/account.jest.js b/lib/__tests__/account.jest.js new file mode 100644 index 00000000..9109a50b --- /dev/null +++ b/lib/__tests__/account.jest.js @@ -0,0 +1,466 @@ +import { + getInboxIndex, + writeInboxIndex, + getInbox, + addressedOnlyToMe, + acceptDM, + isMyPost, + isFollowing, + isFollower, + isMention, + isReplyToMyPost, + createActor, + createWebfinger, + addNotification, + writeNotifications, + getNotifications, + getBoosts, + writeBoosts, + isBlocked, + getBlocks, + writeFollowers, + getFollowers, + writeFollowing, + getFollowing, + writeLikes, + getLikes, + getAccount +} from '../account'; +import * as storage from '../storage'; +import { ActivityPub } from '../ActivityPub'; +import path from 'path'; +import fs from 'fs'; + +import 'node-fetch'; + +jest.mock('node-fetch', () => jest.fn()); + +const testFileDirectoryPath = 'lib/__tests__/files/'; + +afterEach(() => { + jest.restoreAllMocks(); +}); + +describe('Tests for getInboxIndex', () => { + test('Check getting inbox index successfully', () => { + jest.replaceProperty(storage, 'pathToDMs', testFileDirectoryPath + 'dms/'); + + const expectedInboxIndex = { + id: 'inboxes', + 'justin@shuttlecraft.com': { + lastRead: 1672531200000, + latest: 1672531200000 + } + }; + expect(getInboxIndex()).toStrictEqual(expectedInboxIndex); + }); +}); + +describe('Tests for writeInboxIndex', () => { + const inboxPath = testFileDirectoryPath + 'dms/inboxes.json'; + + test('Check writing inbox index successfully', () => { + fs.unlinkSync(inboxPath); + expect(fs.existsSync(inboxPath)).toBe(false); + + jest.replaceProperty(storage, 'pathToDMs', testFileDirectoryPath + 'dms/'); + + const expectedInboxes = { id: 'inboxes' }; + writeInboxIndex(expectedInboxes); + const jsonRaw = fs.readFileSync(inboxPath); + expect(JSON.parse(jsonRaw)).toStrictEqual(expectedInboxes); + }); +}); + +describe('Tests for getInbox', () => { + test('Check getting inbox successfully', () => { + jest.replaceProperty(storage, 'pathToDMs', testFileDirectoryPath + 'dms/'); + + const expectedInbox = ['firstMessage']; + expect(getInbox('justin@shuttlecraft.com')).toStrictEqual(expectedInbox); + }); +}); + +describe('Tests for addressedOnlyToMe', () => { + test('Check that the activity is only addressed to me', () => { + jest.spyOn(ActivityPub, 'actor', 'get').mockReturnValue({ id: 'justin' }); + + const activity = { to: ['justin'], cc: [] }; + + expect(addressedOnlyToMe(activity)).toBe(true); + }); + + test('Check that the activity is addressed to someone that is not me', () => { + jest.spyOn(ActivityPub, 'actor', 'get').mockReturnValue({ id: 'justin' }); + + const activity = { to: ['jay'], cc: [] }; + + expect(addressedOnlyToMe(activity)).toBe(false); + }); + + test('Check that the activity is addressed to more than just me', () => { + jest.spyOn(ActivityPub, 'actor', 'get').mockReturnValue({ id: 'justin' }); + + const activity = { to: ['justin'], cc: ['jay'] }; + + expect(addressedOnlyToMe(activity)).toBe(false); + }); +}); + +describe('Tests for deleteObject', () => {}); + +describe('Tests for acceptDM', () => { + test('Check accepting DM', () => { + jest.replaceProperty(storage, 'pathToDMs', testFileDirectoryPath + 'dms/'); + jest.spyOn(ActivityPub, 'actor', 'get').mockReturnValue({ id: 'justin' }); + + const dm = { message: 'hello', attributedTo: 'jay' }; + const inboxUser = 'justin@shuttlecraft.com'; + acceptDM(dm, inboxUser); + const inbox = getInbox(inboxUser); + expect(inbox).toStrictEqual(['firstMessage', { message: 'hello', attributedTo: 'jay' }]); + inbox.pop(); + const inboxPath = path.resolve(storage.pathToDMs, `${inboxUser}.json`); + storage.writeJSONDictionary(inboxPath, inbox); + }); + + test('Check sending outbound DM', () => { + jest.replaceProperty(storage, 'pathToDMs', testFileDirectoryPath + 'dms/'); + jest.spyOn(ActivityPub, 'actor', 'get').mockReturnValue({ id: 'justin' }); + const mockDate = new Date('2023-01-01T00:00:00Z'); + jest.spyOn(global, 'Date').mockImplementation(() => mockDate); + + const dm = { message: 'hi', attributedTo: 'justin' }; + const inboxUser = 'justin@shuttlecraft.com'; + acceptDM(dm, inboxUser); + const inbox = getInbox(inboxUser); + expect(inbox).toStrictEqual(['firstMessage', { message: 'hi', attributedTo: 'justin' }]); + inbox.pop(); + const inboxPath = path.resolve(storage.pathToDMs, `${inboxUser}.json`); + storage.writeJSONDictionary(inboxPath, inbox); + + const expectedInboxIndex = { + id: 'inboxes', + 'justin@shuttlecraft.com': { + lastRead: 1672531200000, + latest: 1672531200000 + } + }; + expect(getInboxIndex()).toStrictEqual(expectedInboxIndex); + }); +}); + +describe('Tests for isMyPost', () => { + test('Check if a post is my post', () => { + const { DOMAIN } = process.env; + const activity = { + id: `https://${DOMAIN}/m/` + }; + + expect(isMyPost(activity)).toBe(true); + }); + + test('Check if a post is not my post', () => { + const activity = { + id: 'https://garbage/m/' + }; + + expect(isMyPost(activity)).toBe(false); + }); +}); + +describe('Tests for isFollowing', () => { + test('Check with someone I am following', () => { + jest.replaceProperty(storage, 'followingFile', testFileDirectoryPath + 'following.json'); + + expect(isFollowing('justin')).toBe(true); + }); + + test('Check with someone I am not following,', () => { + jest.replaceProperty(storage, 'followingFile', testFileDirectoryPath + 'following.json'); + + expect(isFollowing('aditya')).toBe(false); + }); +}); + +describe('Tests for isFollower', () => { + test('Check with someone that is a follower', () => { + jest.replaceProperty(storage, 'followersFile', testFileDirectoryPath + 'followers.json'); + + expect(isFollower('aditya')).toBe(true); + }); + + test('Check with someone that is not a follower', () => { + jest.replaceProperty(storage, 'followersFile', testFileDirectoryPath + 'followers.json'); + + expect(isFollower('justin')).toBe(false); + }); +}); + +describe('Tests for isMention', () => { + test('Check with activity that is mention', () => { + jest.spyOn(ActivityPub, 'actor', 'get').mockReturnValue({ id: 'justin' }); + + const activity = { tag: [{ type: 'Mention', href: 'justin' }] }; + expect(isMention(activity)).toBe(true); + }); + + test('Check with activity that is not mention', () => { + const activity = {}; + expect(isMention(activity)).toBe(undefined); + }); +}); + +describe('Tests for isReplyToMyPost', () => { + test('Check with activity that is a reply to my post', () => { + const { DOMAIN } = process.env; + const activity = { inReplyTo: `https://${DOMAIN}/m/justin` }; + expect(isReplyToMyPost(activity)).toBe(true); + }); + + test('Check with activity that is not a reply to my post', () => { + const activity = { inReplyTo: 'test' }; + expect(isReplyToMyPost(activity)).toBe(false); + }); +}); + +describe('Tests for isReplyToFollowing', () => {}); + +describe('Tests for createActor', () => { + test('Check successful', () => { + const expectedActor = { + '@context': ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'], + bio: 'hello', + followers: 'https://shuttlecraft.com/u/justin/followers', + icon: { + mediaType: 'image/jpg', + type: 'Image', + url: 'https://www.shutterstock.com/image-vector/user-profile-icon-vector-avatar-600nw-2247726673.jpg' + }, + id: 'https://shuttlecraft.com/u/justin', + image: { + mediaType: 'image/png', + type: 'Image', + url: 'https://static.vecteezy.com/system/resources/thumbnails/011/125/580/small/torn-light-blue-paper-with-white-copyspace-for-your-message-png.png' + }, + inbox: 'https://shuttlecraft.com/api/inbox', + name: 'justin', + outbox: 'https://shuttlecraft.com/api/outbox', + preferredUsername: 'justin', + publicKey: { + id: 'https://shuttlecraft.com/u/justin#main-key', + owner: 'https://shuttlecraft.com/u/justin', + publicKeyPem: 'testPublicKey' + }, + type: 'Person', + url: 'https://shuttlecraft.com/' + }; + const createdActor = createActor('justin', 'shuttlecraft.com', 'testPublicKey', 'hello'); + expect(createdActor).toStrictEqual(expectedActor); + }); +}); + +describe('Tests for createWebfinger', () => { + test('Check successful', () => { + const expectedWebfinger = { + subject: 'acct:justin@shuttlecraft.com', + links: [ + { + rel: 'self', + type: 'application/activity+json', + href: 'https://shuttlecraft.com/u/justin' + } + ] + }; + + expect(createWebfinger('justin', 'shuttlecraft.com')).toStrictEqual(expectedWebfinger); + }); +}); + +describe('Tests for getOutboxPosts', () => {}); + +describe('Tests for addNotification', () => { + test('Check successful', () => { + jest.replaceProperty(storage, 'notificationsFile', testFileDirectoryPath + 'notifications.json'); + const mockDate = new Date('2023-01-01T00:00:00Z'); + jest.spyOn(global, 'Date').mockImplementation(() => mockDate); + + const notificationToAdd = { message: 'testNotification' }; + addNotification(notificationToAdd); + + const expectedNotifications = [ + 'notification', + { + time: 1672531200000, + notification: { message: 'testNotification' } + } + ]; + expect(getNotifications()).toStrictEqual(expectedNotifications); + }); +}); + +describe('Tests for writeNotifications', () => { + const notificationsPath = testFileDirectoryPath + 'notifications.json'; + + test('Check successful', () => { + fs.unlinkSync(notificationsPath); + expect(fs.existsSync(notificationsPath)).toBe(false); + + jest.replaceProperty(storage, 'notificationsFile', notificationsPath); + + const expectedNotifications = ['notification']; + writeNotifications(expectedNotifications); + const jsonRaw = fs.readFileSync(notificationsPath); + expect(JSON.parse(jsonRaw)).toStrictEqual(expectedNotifications); + }); +}); + +describe('Tests for getNotifications', () => { + test('Check successful', () => { + jest.replaceProperty(storage, 'notificationsFile', testFileDirectoryPath + 'notifications.json'); + + const expectedNotifications = ['notification']; + expect(getNotifications()).toStrictEqual(expectedNotifications); + }); +}); + +describe('Tests for isBlocked', () => { + test('Check actor that is a banned user', () => { + jest.replaceProperty(storage, 'blocksFile', testFileDirectoryPath + 'blocks.json'); + + const actor = 'aditya'; + expect(isBlocked(actor)).toBe(true); + }); + + test('Check actor that is from a banned domain', () => { + jest.replaceProperty(storage, 'blocksFile', testFileDirectoryPath + 'blocks.json'); + + const actor = 'https://blockedDomain.com/enze'; + expect(isBlocked(actor)).toBe(true); + }); + + test('Check actor that is not a banned user', () => { + jest.replaceProperty(storage, 'blocksFile', testFileDirectoryPath + 'blocks.json'); + + const actor = 'justin'; + expect(isBlocked(actor)).toBe(false); + }); +}); + +describe('Tests for getBlocks', () => { + test('Check successful', () => { + jest.replaceProperty(storage, 'blocksFile', testFileDirectoryPath + 'blocks.json'); + + const expectedBlocks = ['aditya', 'kashish', 'https://blockedDomain.com']; + expect(getBlocks()).toStrictEqual(expectedBlocks); + }); +}); + +describe('Tests for writeFollowers', () => { + const followersPath = testFileDirectoryPath + 'followers.json'; + + test('Check successful', () => { + fs.unlinkSync(followersPath); + expect(fs.existsSync(followersPath)).toBe(false); + + jest.replaceProperty(storage, 'followersFile', followersPath); + + const expectedFollowers = ['aditya', 'kashish']; + writeFollowers(expectedFollowers); + const jsonRaw = fs.readFileSync(followersPath); + expect(JSON.parse(jsonRaw)).toStrictEqual(expectedFollowers); + }); +}); + +describe('Tests for getFollowers', () => { + test('Check successful', () => { + jest.replaceProperty(storage, 'followersFile', testFileDirectoryPath + 'followers.json'); + + const expectedFollowers = ['aditya', 'kashish']; + expect(getFollowers()).toStrictEqual(expectedFollowers); + }); +}); + +describe('Tests for writeFollowing', () => { + const followingPath = testFileDirectoryPath + 'following.json'; + + test('Check successful', () => { + fs.unlinkSync(followingPath); + expect(fs.existsSync(followingPath)).toBe(false); + + jest.replaceProperty(storage, 'followingFile', followingPath); + + const expectedFollowing = [{ actorId: 'justin' }, { actorId: 'jay' }]; + writeFollowing(expectedFollowing); + const jsonRaw = fs.readFileSync(followingPath); + expect(JSON.parse(jsonRaw)).toStrictEqual(expectedFollowing); + }); +}); + +describe('Tests for getFollowing', () => { + test('Check successful', () => { + jest.replaceProperty(storage, 'followingFile', testFileDirectoryPath + 'following.json'); + + const expectedFollowing = [{ actorId: 'justin' }, { actorId: 'jay' }]; + expect(getFollowing()).toStrictEqual(expectedFollowing); + }); +}); + +describe('Tests for writeBoosts', () => { + const boostsPath = testFileDirectoryPath + 'boosts.json'; + + test('Check successful', () => { + fs.unlinkSync(boostsPath); + expect(fs.existsSync(boostsPath)).toBe(false); + + jest.replaceProperty(storage, 'boostsFile', boostsPath); + + const expectedBoosts = { id: 'boosts' }; + writeBoosts(expectedBoosts); + const jsonRaw = fs.readFileSync(boostsPath); + expect(JSON.parse(jsonRaw)).toStrictEqual(expectedBoosts); + }); +}); + +describe('Tests for getBoosts', () => { + test('Check successful', () => { + jest.replaceProperty(storage, 'boostsFile', testFileDirectoryPath + 'boosts.json'); + + const expectedBoosts = { id: 'boosts' }; + expect(getBoosts()).toStrictEqual(expectedBoosts); + }); +}); + +describe('Tests for writeLikes', () => { + const likesPath = testFileDirectoryPath + 'likes.json'; + + test('Check successful', () => { + fs.unlinkSync(likesPath); + expect(fs.existsSync(likesPath)).toBe(false); + + jest.replaceProperty(storage, 'likesFile', likesPath); + + const expectedLikes = { id: 'likes' }; + writeLikes(expectedLikes); + const jsonRaw = fs.readFileSync(likesPath); + expect(JSON.parse(jsonRaw)).toStrictEqual(expectedLikes); + }); +}); + +describe('Tests for getLikes', () => { + test('Check successful', () => { + jest.replaceProperty(storage, 'likesFile', testFileDirectoryPath + 'likes.json'); + + const expectedLikes = { id: 'likes' }; + expect(getLikes()).toStrictEqual(expectedLikes); + }); +}); + +describe('Tests for getAccount', () => { + test('Check successful', () => { + jest.replaceProperty(storage, 'accountFile', testFileDirectoryPath + 'account.json'); + + const expectedAccount = { id: 'account' }; + expect(getAccount()).toStrictEqual(expectedAccount); + }); +}); diff --git a/lib/__tests__/files/account.json b/lib/__tests__/files/account.json new file mode 100644 index 00000000..4450133b --- /dev/null +++ b/lib/__tests__/files/account.json @@ -0,0 +1,3 @@ +{ + "id": "account" +} \ No newline at end of file diff --git a/lib/__tests__/files/blocks.json b/lib/__tests__/files/blocks.json new file mode 100644 index 00000000..f6b5d5e0 --- /dev/null +++ b/lib/__tests__/files/blocks.json @@ -0,0 +1,5 @@ +[ + "aditya", + "kashish", + "https://blockedDomain.com" +] \ No newline at end of file diff --git a/lib/__tests__/files/boosts.json b/lib/__tests__/files/boosts.json new file mode 100644 index 00000000..47e9152d --- /dev/null +++ b/lib/__tests__/files/boosts.json @@ -0,0 +1,3 @@ +{ + "id": "boosts" +} \ No newline at end of file diff --git a/lib/__tests__/files/dms/inboxes.json b/lib/__tests__/files/dms/inboxes.json new file mode 100644 index 00000000..1a23d66e --- /dev/null +++ b/lib/__tests__/files/dms/inboxes.json @@ -0,0 +1,7 @@ +{ + "id": "inboxes", + "justin@shuttlecraft.com": { + "lastRead": 1672531200000, + "latest": 1672531200000 + } +} \ No newline at end of file diff --git a/lib/__tests__/files/dms/justin@shuttlecraft.com.json b/lib/__tests__/files/dms/justin@shuttlecraft.com.json new file mode 100644 index 00000000..1f2814df --- /dev/null +++ b/lib/__tests__/files/dms/justin@shuttlecraft.com.json @@ -0,0 +1,3 @@ +[ + "firstMessage" +] \ No newline at end of file diff --git a/lib/__tests__/files/followers.json b/lib/__tests__/files/followers.json new file mode 100644 index 00000000..8339b13e --- /dev/null +++ b/lib/__tests__/files/followers.json @@ -0,0 +1,4 @@ +[ + "aditya", + "kashish" +] \ No newline at end of file diff --git a/lib/__tests__/files/following.json b/lib/__tests__/files/following.json new file mode 100644 index 00000000..e580f5f4 --- /dev/null +++ b/lib/__tests__/files/following.json @@ -0,0 +1,8 @@ +[ + { + "actorId": "justin" + }, + { + "actorId": "jay" + } +] \ No newline at end of file diff --git a/lib/__tests__/files/likedata.json b/lib/__tests__/files/likedata.json new file mode 100644 index 00000000..17562e09 --- /dev/null +++ b/lib/__tests__/files/likedata.json @@ -0,0 +1,5 @@ +{ + "id": "abc", + "likes": [], + "boosts": [] +} \ No newline at end of file diff --git a/lib/__tests__/files/likes.json b/lib/__tests__/files/likes.json new file mode 100644 index 00000000..7ffd8504 --- /dev/null +++ b/lib/__tests__/files/likes.json @@ -0,0 +1,3 @@ +{ + "id": "likes" +} \ No newline at end of file diff --git a/lib/__tests__/files/notifications.json b/lib/__tests__/files/notifications.json new file mode 100644 index 00000000..02b8cb07 --- /dev/null +++ b/lib/__tests__/files/notifications.json @@ -0,0 +1,3 @@ +[ + "notification" +] \ No newline at end of file diff --git a/lib/__tests__/files/readJSONDictionary.json b/lib/__tests__/files/readJSONDictionary.json new file mode 100644 index 00000000..7f3445f9 --- /dev/null +++ b/lib/__tests__/files/readJSONDictionary.json @@ -0,0 +1,3 @@ +{ + "id": "test" +} \ No newline at end of file diff --git a/lib/__tests__/notes.jest.js b/lib/__tests__/notes.jest.js new file mode 100644 index 00000000..e0a11d31 --- /dev/null +++ b/lib/__tests__/notes.jest.js @@ -0,0 +1,149 @@ +import fs from 'fs'; +import { + INDEX, + deleteActivityFromIndex, + addActivityToIndex, + getLikesFileName, + writeJSONDictionary +} from '../storage.js'; +import { getLikesForNote, getReplyCountForNote, recordLike, recordBoost, recordUndoLike } from '../notes.js'; + +beforeEach(() => { + jest.resetModules(); +}); + +jest.mock('../storage', () => ({ + ...jest.requireActual('../storage'), + getLikesFileName: jest.fn(() => 'lib/__tests__/files/likedata.json') +})); + +describe('Tests for getLikesForNote', () => { + test('Check if the output matches', () => { + const mockDate = new Date('2023-01-01T00:00:00Z'); + const spy = jest.spyOn(global, 'Date').mockImplementation(() => mockDate); + const id = 'abc'; + const attributedTo = 'justin'; + const published = '2023-01-01T00:00:00Z'; + const inReplyTo = 'ever'; + const note = { id: id, attributedTo: attributedTo, published: published, inReplyTo: inReplyTo }; + + addActivityToIndex(note); + + const content = { id: 'abc', likes: [], boosts: [] }; + + expect(getLikesForNote(id)).toStrictEqual(content); + deleteActivityFromIndex(id); + spy.mockRestore(); + }); +}); + +describe('Tests for getReplyCountForNote', () => { + test('Check on empty array', () => { + INDEX.splice(0, INDEX.length); + expect(getReplyCountForNote('A')).toBe(0); + }); + + test('Check with existing inReplyTo in INDEX', () => { + INDEX.splice(0, INDEX.length); + INDEX.push({ id: '1', inReplyTo: 'AB' }, { id: '2', inReplyTo: 'AB' }, { id: '3', inReplyTo: 'AC' }); + expect(getReplyCountForNote('AB')).toBe(2); + }); + + test('Check with non-existing inReplyTo in INDEX', () => { + INDEX.splice(0, INDEX.length); + INDEX.push({ id: '1', inReplyTo: 'AB' }, { id: '2', inReplyTo: 'CD' }); + expect(getReplyCountForNote('AC')).toBe(0); + }); +}); + +describe('Tests for recordLike', () => { + test('Check for no actor like records', () => { + const mockDate = new Date('2023-01-01T00:00:00Z'); + const spy = jest.spyOn(global, 'Date').mockImplementation(() => mockDate); + const id = 'abc'; + const attributedTo = 'justin'; + const published = '2023-01-01T00:00:00Z'; + const inReplyTo = 'ever'; + const note = { id: id, attributedTo: attributedTo, published: published, inReplyTo: inReplyTo }; + + addActivityToIndex(note); + const request = { actor: 'Ever', object: id }; + + const old_likes = getLikesForNote(id); + + expect(old_likes.likes.indexOf('Ever')).toBeLessThan(0); + recordLike(request); + + const likes = getLikesForNote(id); + expect(likes.likes.indexOf('Ever')).toBeGreaterThanOrEqual(0); + + const fileName = getLikesFileName(id); + const fileContent = fs.readFileSync(fileName, 'utf-8'); + + expect(fileContent).toMatch(JSON.stringify(likes, null, 2)); + deleteActivityFromIndex(id); + + spy.mockRestore(); + }); +}); + +describe('Tests for recordBoost', () => { + test('Check for no actor boost records', () => { + const mockDate = new Date('2023-01-01T00:00:00Z'); + const spy = jest.spyOn(global, 'Date').mockImplementation(() => mockDate); + const id = 'abc'; + const attributedTo = 'justin'; + const published = '2023-01-01T00:00:00Z'; + const inReplyTo = 'ever'; + const note = { id: id, attributedTo: attributedTo, published: published, inReplyTo: inReplyTo }; + + addActivityToIndex(note); + const request = { actor: 'def', object: id }; + + const old_likes = getLikesForNote(id); + + expect(old_likes.boosts.indexOf('def')).toBeLessThan(0); + recordBoost(request); + + const likes = getLikesForNote(id); + expect(likes.boosts.indexOf('def')).toBeGreaterThanOrEqual(0); + + const fileName = getLikesFileName(id); + const fileContent = fs.readFileSync(fileName, 'utf-8'); + + expect(fileContent).toMatch(JSON.stringify(likes, null, 2)); + deleteActivityFromIndex(id); + + spy.mockRestore(); + }); +}); + +describe('Tests for recordUndoLike', () => { + test('Check when undoing a like', () => { + const mockDate = new Date('2023-01-01T00:00:00Z'); + const spy = jest.spyOn(global, 'Date').mockImplementation(() => mockDate); + const id = 'abc'; + const attributedTo = 'justin'; + const published = '2023-01-01T00:00:00Z'; + const inReplyTo = 'ever'; + const note = { id: id, attributedTo: attributedTo, published: published, inReplyTo: inReplyTo }; + + addActivityToIndex(note); + const request = { actor: 'Ever', object: id }; + + recordUndoLike(request); + + const likes = getLikesForNote(id); + expect(likes.likes.indexOf('Ever')).toBeLessThan(0); + + const fileName = getLikesFileName(id); + const fileContent = fs.readFileSync(fileName, 'utf-8'); + + expect(fileContent).toMatch(JSON.stringify(likes, null, 2)); + deleteActivityFromIndex(id); + + likes.boosts = []; + writeJSONDictionary(fileName, likes); + spy.mockRestore(); + }); +}); diff --git a/lib/__tests__/storage.jest.js b/lib/__tests__/storage.jest.js new file mode 100644 index 00000000..99b3a195 --- /dev/null +++ b/lib/__tests__/storage.jest.js @@ -0,0 +1,302 @@ +import { + pathToFiles, + pathToPosts, + isMyPost, + INDEX, + isIndexed, + fromIndex, + readJSONDictionary, + writeJSONDictionary, + CACHE, + deleteJSONDictionary, + addFailureToIndex, + addActivityToIndex, + deleteActivityFromIndex, + getFileName, + getLikesFileName, + createFileName +} from '../storage.js'; +import fs from 'fs'; +import path from 'path'; +import md5 from 'md5'; + +const zeroPad = num => { + if (num < 10) { + return `0${num}`; + } else return num; +}; + +describe('Tests for isMyPost', () => { + test('Check if a post is my post', () => { + const { DOMAIN } = process.env; + const activityId = `https://${DOMAIN}/m/`; + + expect(isMyPost(activityId)).toBe(true); + }); + + test('Check if a post is not my post', () => { + const activityId = `https://garbage/m/`; + + expect(isMyPost(activityId)).toBe(false); + }); +}); + +describe('Tests for isIndexed', () => { + test('Check on empty array', () => { + INDEX.splice(0, INDEX.length); + expect(isIndexed('abc')).toBe(false); + }); + + test('Check with existing id in array', () => { + INDEX.splice(0, INDEX.length); + INDEX.push({ id: 'abc' }); + expect(isIndexed('abc')).toBe(true); + }); + + test('Check with non-existing id in array', () => { + INDEX.splice(0, INDEX.length); + INDEX.push({ id: 'abc' }); + expect(isIndexed('def')).toBe(false); + }); +}); + +describe('Tests for fromIndex', () => { + test('Check on empty array', () => { + INDEX.splice(0, INDEX.length); + expect(fromIndex('abc')).toBe(false); + }); + + test('Check with existing id in array', () => { + INDEX.splice(0, INDEX.length); + INDEX.push({ id: 'abc' }); + expect(fromIndex('abc')).toStrictEqual({ id: 'abc' }); + }); + + test('Check with non-existing id in array', () => { + INDEX.splice(0, INDEX.length); + INDEX.push({ id: 'abc' }); + expect(fromIndex('def')).toBe(false); + deleteActivityFromIndex('abc'); + }); +}); + +describe('Tests for readJSONDictionary', () => { + test('Check with non-existing path', () => { + const mockDate = new Date('2023-01-01T00:00:00Z'); + const spy = jest.spyOn(global, 'Date').mockImplementation(() => mockDate); + + const path = 'files/garbage'; + + readJSONDictionary(path); + + expect(CACHE[path]).toStrictEqual({ time: mockDate.getTime(), lastAccess: mockDate.getTime(), contents: [] }); + spy.mockRestore(); + }); + + test('Check with existing path and no cache hit', () => { + const mockDate = new Date('2023-01-01T00:00:00Z'); + const spy = jest.spyOn(global, 'Date').mockImplementation(() => mockDate); + + const path = 'lib/__tests__/files/readJSONDictionary.json'; + + readJSONDictionary(path); + + const jsonString = '{"id": "test"}'; + + expect(CACHE[path]).toStrictEqual({ + time: mockDate.getTime(), + lastAccess: mockDate.getTime(), + contents: JSON.parse(jsonString) + }); + spy.mockRestore(); + }); + + test('Check with existing path and cache hit', () => { + const mockDate = new Date('2022-01-01T00:00:00Z'); + const cachedDate = new Date('2023-01-01T00:00:00Z'); + const spy = jest.spyOn(global, 'Date').mockImplementation(() => mockDate); + + const path = 'lib/__tests__/files/readJSONDictionary.json'; + + readJSONDictionary(path); + + const jsonString = '{"id": "test"}'; + + expect(CACHE[path]).toStrictEqual({ + time: cachedDate.getTime(), + lastAccess: mockDate.getTime(), + contents: JSON.parse(jsonString) + }); + spy.mockRestore(); + }); +}); + +describe('Tests for writeJSONDictionary', () => { + test('Check successful', () => { + const mockDate = new Date('2023-01-01T00:00:00Z'); + const spy = jest.spyOn(global, 'Date').mockImplementation(() => mockDate); + + const path = 'lib/__tests__/files/writeJSONDictionary.json'; + const data = { id: 'test' }; + + writeJSONDictionary(path, data); + + expect(CACHE[path]).toEqual({ + time: mockDate.getTime(), + lastAccess: mockDate.getTime(), + contents: data + }); + const fileContent = fs.readFileSync(path, 'utf-8'); + expect(fileContent).toMatch(JSON.stringify(data, null, 2)); + spy.mockRestore(); + }); +}); + +describe('Tests for deleteJSONDictionary', () => { + test('Check with existing path', () => { + const path = 'lib/__tests__/files/writeJSONDictionary.json'; + + deleteJSONDictionary(path); + + expect(fs.existsSync(path)).toBe(false); + expect(CACHE[path]).toBe(undefined); + }); +}); + +describe('Tests for addFailureToIndex', () => { + test('Check successful', () => { + const mockDate = new Date('2023-01-01T00:00:00Z'); + const id = 'def'; + + const note = { id: id, time: mockDate.getTime(), status: 'error' }; + + addFailureToIndex(note); + + const failure = fromIndex(id); + expect(failure.type).toBe('fail'); + expect(failure.id).toBe(id); + expect(failure.published).toBe(mockDate.getTime()); + expect(failure.status).toBe('error'); + + deleteActivityFromIndex(id); + }); +}); + +describe('Tests for addActivityToIndex', () => { + test('Check successful', () => { + const mockDate = new Date('2023-01-01T00:00:00Z'); + const id = 'ghi'; + const attributedTo = 'justin'; + const published = '2023-01-01T00:00:00Z'; + const inReplyTo = 'ever'; + const note = { id: id, attributedTo: attributedTo, published: published, inReplyTo: inReplyTo }; + + addActivityToIndex(note); + + const activity = fromIndex(id); + expect(activity.type).toBe('activity'); + expect(activity.id).toBe(id); + expect(activity.actor).toBe(attributedTo); + expect(activity.published).toBe(mockDate.getTime()); + expect(activity.inReplyTo).toBe(inReplyTo); + + deleteActivityFromIndex(id); + }); +}); + +describe('Tests for deleteActivityFromIndex', () => { + test('Check successful', () => { + const mockDate = new Date('2023-01-01T00:00:00Z'); + const id = 'jkl'; + const attributedTo = 'justin'; + const published = '2023-01-01T00:00:00Z'; + const inReplyTo = 'ever'; + const note = { id: id, attributedTo: attributedTo, published: published, inReplyTo: inReplyTo }; + + addActivityToIndex(note); + + const activity = fromIndex(id); + expect(activity.type).toBe('activity'); + expect(activity.id).toBe(id); + expect(activity.actor).toBe(attributedTo); + expect(activity.published).toBe(mockDate.getTime()); + expect(activity.inReplyTo).toBe(inReplyTo); + + deleteActivityFromIndex(id); + + expect(INDEX.findIndex(idx => idx.id === id)).toBe(-1); + }); +}); + +describe('Tests for getFileName', () => { + test('Check when file not cached', () => { + const mockDate = new Date('2023-01-01T00:00:00Z'); + const id = 'abc'; + const attributedTo = 'justin'; + const published = '2023-01-01T00:00:00Z'; + const inReplyTo = 'ever'; + const note = { id: id, attributedTo: attributedTo, published: published, inReplyTo: inReplyTo }; + + addActivityToIndex(note); + + const folder = mockDate.getFullYear() + '/' + zeroPad(mockDate.getMonth() + 1) + '-' + zeroPad(mockDate.getDate()); + + expect(getFileName(id)).toBe(path.resolve(pathToFiles, folder, `${md5(id)}.json`)); + }); + test('Check when file is cached', () => { + const mockDate = new Date('2023-01-01T00:00:00Z'); + const id = 'abc'; + + const folder = mockDate.getFullYear() + '/' + zeroPad(mockDate.getMonth() + 1) + '-' + zeroPad(mockDate.getDate()); + + expect(getFileName(id)).toBe(path.resolve(pathToFiles, folder, `${md5(id)}.json`)); + deleteActivityFromIndex(id); + }); +}); + +describe('Tests for getLikesFileName', () => { + test('Check when file not cached', () => { + const mockDate = new Date('2023-01-01T00:00:00Z'); + const id = 'abc'; + const attributedTo = 'justin'; + const published = '2023-01-01T00:00:00Z'; + const inReplyTo = 'ever'; + const note = { id: id, attributedTo: attributedTo, published: published, inReplyTo: inReplyTo }; + + addActivityToIndex(note); + + const folder = mockDate.getFullYear() + '/' + zeroPad(mockDate.getMonth() + 1) + '-' + zeroPad(mockDate.getDate()); + + expect(getLikesFileName(id)).toBe(path.resolve(pathToPosts, folder, `${md5(id)}.likes.json`)); + }); + test('Check when file is cached', () => { + const mockDate = new Date('2023-01-01T00:00:00Z'); + const id = 'abc'; + + const folder = mockDate.getFullYear() + '/' + zeroPad(mockDate.getMonth() + 1) + '-' + zeroPad(mockDate.getDate()); + + expect(getLikesFileName(id)).toBe(path.resolve(pathToPosts, folder, `${md5(id)}.likes.json`)); + deleteActivityFromIndex(id); + }); +}); + +describe('Tests for createFileName', () => { + test('Check successful', () => { + const mockDate = new Date('2023-01-01T00:00:00Z'); + const id = 'jkl'; + const attributedTo = 'justin'; + const published = '2023-01-01T00:00:00Z'; + const inReplyTo = 'ever'; + const note = { id: id, attributedTo: attributedTo, published: published, inReplyTo: inReplyTo }; + + addActivityToIndex(note); + + const activity = fromIndex(id); + + const folder = mockDate.getFullYear() + '/' + zeroPad(mockDate.getMonth() + 1) + '-' + zeroPad(mockDate.getDate()); + + expect(createFileName(activity)).toBe(path.resolve(pathToFiles, folder, `${md5(id)}.json`)); + expect(fs.existsSync(path.resolve(pathToFiles, folder))).toBe(true); + deleteActivityFromIndex(id); + }); +}); diff --git a/lib/account.js b/lib/account.js index 137998bd..756d8150 100644 --- a/lib/account.js +++ b/lib/account.js @@ -31,17 +31,29 @@ const logger = debug('ono:account'); const { DOMAIN } = process.env; +/** + * The function `getInboxIndex` returns the inbox index by reading a JSON dictionary from a specified + * path. + * @returns The function `getInboxIndex` returns the `inboxIndex` object. + */ export const getInboxIndex = () => { - const inboxIndexPath = path.resolve(pathToDMs, `inboxes.json`); + const inboxIndexPath = path.resolve(pathToDMs, 'inboxes.json'); const inboxIndex = readJSONDictionary(inboxIndexPath, {}); return inboxIndex; }; +/** + * The function writes data to a JSON file that represents the index of an inbox. + */ export const writeInboxIndex = data => { - const inboxIndexPath = path.resolve(pathToDMs, `inboxes.json`); + const inboxIndexPath = path.resolve(pathToDMs, 'inboxes.json'); writeJSONDictionary(inboxIndexPath, data); }; +/** + * The function `getInbox` retrieves the inbox messages for a given actor ID. + * @returns The function `getInbox` returns the `inbox` array. + */ export const getInbox = actorId => { const username = ActivityPub.getUsername(actorId); @@ -72,6 +84,17 @@ export const addressedOnlyToMe = activity => { return false; }; +/** + * The function `deleteObject` checks if the incoming request is a valid object and if it is a + * "Tombstone" type, then it verifies if the actor is allowed to delete the object and deletes it if + * allowed. + * @param actor - The `actor` parameter represents the user who is performing the delete action. It + * contains information about the user, such as their ID. + * @param incomingRequest - The `incomingRequest` parameter is an object that represents the request to + * delete an object. It contains the following properties: + * @returns a boolean value. It returns `false` in two cases: if the `incomingRequest.object` is not an + * object or if its type is not 'Tombstone'. It returns `true` in all other cases. + */ export const deleteObject = async (actor, incomingRequest) => { if (typeof incomingRequest.object !== 'object') { return false; @@ -79,9 +102,6 @@ export const deleteObject = async (actor, incomingRequest) => { if (incomingRequest.object.type !== 'Tombstone') { return false; } - // TODO: support delete of user. - // remove user, remove follow, following, etc. - // remove all posts by user. try { const activity = await getActivity(incomingRequest.object.id); if (activity.attributedTo !== actor.id) { @@ -111,6 +131,14 @@ export const deleteObject = async (actor, incomingRequest) => { return true; }; +/** + * The `acceptDM` function accepts a direct message (DM) and adds it to the inbox of a specified user, + * updating the inbox index and marking the last read timestamp if the DM is an outbound message. + * @param dm - The `dm` parameter represents the direct message that is being accepted. It is an object + * that contains information about the message, such as its content, sender, and timestamp. + * @param inboxUser - The `inboxUser` parameter represents the user whose inbox the direct message (DM) + * will be added to. + */ export const acceptDM = (dm, inboxUser) => { const inboxIndex = getInboxIndex(); const inbox = getInbox(inboxUser); @@ -137,32 +165,61 @@ export const acceptDM = (dm, inboxUser) => { writeInboxIndex(inboxIndex); }; +/** + * The function checks if the activity's ID starts with a specific domain and returns a boolean value. + * @returns a boolean value indicating whether the given activity's ID starts with the string + * "https://DOMAIN/m/". + */ export const isMyPost = activity => { return activity.id.startsWith(`https://${DOMAIN}/m/`); }; +/** + * The function checks if a given actorId is present in the list of following. + * @returns a boolean value indicating whether the actor with the specified actorId is being followed + * or not. + */ export const isFollowing = actorId => { const following = getFollowing(); return following.some(f => f.actorId === actorId); }; +/** + * The function `isFollower` checks if a given `actorId` is included in the list of followers. + * @returns a boolean value indicating whether the given actorId is included in the list of followers. + */ export const isFollower = actorId => { const followers = getFollowers(); return followers.includes(actorId); }; +/** + * The function `isMention` checks if an activity contains a mention of the current user. + * @returns The function `isMention` returns a boolean value. It returns `true` if the `activity` + * object has a `tag` property that is an array and contains at least one element that has a `type` + * property equal to `'Mention'` and an `href` property equal to `ActivityPub.actor.id`. Otherwise, it + * returns `false`. + */ export const isMention = activity => { return activity.tag?.some(tag => { return tag.type === 'Mention' && tag.href === ActivityPub.actor.id; }); }; +/** + * The function checks if an activity is a reply to a post with a specific pattern. + * @returns a boolean value indicating whether the given activity is a reply to a post. + */ export const isReplyToMyPost = activity => { // has inReplyTo AND it matches the pattern of our posts. - // TODO: Do we need to ACTUALLY validate that this post exists? return activity.inReplyTo && activity.inReplyTo.startsWith(`https://${DOMAIN}/m/`); }; +/** + * The function checks if a given activity is a reply to a post from an account that is being followed. + * @returns The function isReplyToFollowing returns a boolean value. It returns true if the parent post + * of the given activity is being followed, and false otherwise. + */ export const isReplyToFollowing = async activity => { // fetch the parent, check ITs owner to see if we follow them. try { @@ -176,26 +233,48 @@ export const isReplyToFollowing = async activity => { return false; }; -function createActor(name, domain, pubkey) { +/** + * The above code defines two functions in JavaScript, one for creating an actor object and another for + * creating a webfinger object. + * @param name - The name parameter is the name of the actor or user. It is used to create the actor's + * username and display name. + * @param domain - The domain parameter represents the domain name of the actor's website or platform. + * It is used to construct the URLs for the actor's profile, inbox, outbox, followers, and image/icon + * URLs. + * @param pubkey - The `pubkey` parameter is the public key of the actor. It is a string that + * represents the public key in PEM format. + * @returns The `createActor` function returns an object representing an actor in the ActivityStreams + * format. The `createWebfinger` function returns an object representing a WebFinger response. + */ +export const createActor = (name, domain, pubkey, bio, img) => { + if (typeof img === 'undefined') { + img = 'https://www.shutterstock.com/image-vector/user-profile-icon-vector-avatar-600nw-2247726673.jpg'; + } return { '@context': ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'], id: `https://${domain}/u/${name}`, url: `https://${domain}/`, type: 'Person', name: `${name}`, + bio: `${bio || ''}`, preferredUsername: `${name}`, inbox: `https://${domain}/api/inbox`, outbox: `https://${domain}/api/outbox`, followers: `https://${domain}/u/${name}/followers`, icon: { type: 'Image', - mediaType: 'image/png', - url: `https://${domain}/images/avatar.png` + mediaType: 'image/jpg', + // url: `https://${domain}/images/avatar.png` + // default icon image, later can store locally + // url: 'https://www.shutterstock.com/image-vector/user-profile-icon-vector-avatar-600nw-2247726673.jpg' + // url: `https://${mydomain}/public/images/avatar/${img}`, + url: `${img}` }, image: { type: 'Image', mediaType: 'image/png', - url: `https://${domain}/images/header.png` + // default header image, later can store locally + url: 'https://static.vecteezy.com/system/resources/thumbnails/011/125/580/small/torn-light-blue-paper-with-white-copyspace-for-your-message-png.png' }, publicKey: { id: `https://${domain}/u/${name}#main-key`, @@ -203,9 +282,19 @@ function createActor(name, domain, pubkey) { publicKeyPem: pubkey } }; -} +}; -function createWebfinger(name, domain) { +/** + * The function creates a Webfinger object with a subject and a link. + * @param name - The name parameter represents the username or identifier of the user. It is used to + * construct the subject property of the returned object. + * @param domain - The `domain` parameter represents the domain name of the website or service where + * the webfinger resource is being created. It is used to construct the `subject` and `href` properties + * in the returned object. + * @returns The function `createWebfinger` returns an object with two properties: `subject` and + * `links`. + */ +export const createWebfinger = (name, domain) => { return { subject: `acct:${name}@${domain}`, @@ -217,8 +306,13 @@ function createWebfinger(name, domain) { } ] }; -} +}; +/** + * The function `getOutboxPosts` retrieves a slice of posts from an array, sorts them by date, and + * returns the total number of posts and the retrieved posts. + * @returns The function `getOutboxPosts` returns an object with two properties: `total` and `posts`. + */ export const getOutboxPosts = async offset => { // sort all known posts by date quickly const sortedSlice = INDEX.filter(p => p.type === 'note').sort(sortByDate); @@ -237,6 +331,10 @@ export const getOutboxPosts = async offset => { }; }; +/** + * The function `addNotification` adds a new notification to an array of notifications and writes the + * updated array to storage. + */ export const addNotification = notification => { const notifications = getNotifications(); notifications.push({ @@ -246,19 +344,30 @@ export const addNotification = notification => { writeNotifications(notifications); }; +/** + * The function writes a JSON dictionary of notifications to a file. + * @returns the result of calling the `writeJSONDictionary` function with the `notificationsFile` and + * `notifications` as arguments. + */ export const writeNotifications = notifications => { return writeJSONDictionary(notificationsFile, notifications); }; +/** + * The function `getNotifications` returns the contents of a JSON dictionary stored in a file. + * @returns The function `getNotifications` is returning the result of calling the `readJSONDictionary` + * function with the `notificationsFile` parameter. + */ export const getNotifications = () => { return readJSONDictionary(notificationsFile); }; -// todo: expose an interface for adding to the block list. -// const writeBlocks = (data) => { -// return writeJSONDictionary(blocksFile, data); -// } - +/** + * The function checks if an actor is blocked based on a list of banned users or domains. + * @returns The function `isBlocked` returns a boolean value. It returns `true` if the `actor` is found + * in the `blocks` array or if the `actor` starts with any of the elements in the `blocks` array. + * Otherwise, it returns `false`. + */ export const isBlocked = actor => { const blocks = getBlocks(); return blocks.some(banned => { @@ -273,53 +382,97 @@ export const isBlocked = actor => { }); }; +/** + * The function `getBlocks` returns the contents of a JSON dictionary stored in a file, or an empty + * array if the file does not exist. + * @returns The function `getBlocks` is returning the result of calling the `readJSONDictionary` + * function with the arguments `blocksFile` and an empty array `[]`. + */ export const getBlocks = () => { return readJSONDictionary(blocksFile, []); }; -const writeFollowers = followers => { +/** + * The function "writeFollowers" writes a JSON dictionary of followers to a file. + * @returns The function `writeFollowers` is returning the result of calling the `writeJSONDictionary` + * function with the `followersFile` and `followers` as arguments. + */ +export const writeFollowers = followers => { return writeJSONDictionary(followersFile, followers); }; +/** + * The function `getFollowers` returns the contents of a JSON dictionary stored in the `followersFile` + * variable. + * @returns The function `getFollowers` is returning the result of calling the `readJSONDictionary` + * function with the `followersFile` parameter. + */ export const getFollowers = () => { return readJSONDictionary(followersFile); }; +/** + * The function writes a JSON dictionary of followers to a file. + * @returns the result of calling the `writeJSONDictionary` function with the `followingFile` and + * `followers` as arguments. + */ export const writeFollowing = followers => { return writeJSONDictionary(followingFile, followers); }; +/** + * The function `getFollowing` returns the contents of a JSON dictionary stored in the `followingFile` + * variable. + * @returns The function `getFollowing` is returning the result of calling the `readJSONDictionary` + * function with the `followingFile` parameter. + */ export const getFollowing = () => { - return readJSONDictionary(followingFile).map(f => { - if (typeof f === 'string') { - // map old format to new format just in case - // TODO: remove this before release - return { - id: f, - actorId: f - }; - } else { - return f; - } - }); + return readJSONDictionary(followingFile); }; +/** + * The function `writeBoosts` writes a JSON dictionary to a file. + * @returns the result of calling the `writeJSONDictionary` function with the `boostsFile` and `data` + * parameters. + */ export const writeBoosts = data => { return writeJSONDictionary(boostsFile, data); }; +/** + * The function `getBoosts` returns a JSON dictionary from a file, or an empty array if the file is not + * found. + * @returns The function `getBoosts` is returning the result of calling the `readJSONDictionary` + * function with the `boostsFile` parameter and an empty array as the default value. + */ export const getBoosts = () => { return readJSONDictionary(boostsFile, []); }; +/** + * The function `writeLikes` writes a JSON dictionary of likes to a file. + * @returns the result of calling the `writeJSONDictionary` function with the `likesFile` and `likes` + * as arguments. + */ export const writeLikes = likes => { return writeJSONDictionary(likesFile, likes); }; +/** + * The function `getLikes` returns the contents of a JSON file as a dictionary. + * @returns The function `getLikes` is returning the result of calling the `readJSONDictionary` + * function with the `likesFile` parameter. + */ export const getLikes = () => { return readJSONDictionary(likesFile); }; +/** + * The function `getNote` is an asynchronous function that takes an `id` parameter and returns the + * contents of a JSON file with the corresponding `id` if it exists, otherwise it returns `undefined`. + * @returns a Promise that resolves to the contents of a JSON file if it exists, or undefined if the + * file does not exist or there is an error reading the file. + */ export const getNote = async id => { // const postFile = path.resolve('./', pathToPosts, guid + '.json'); const noteFile = getFileName(id); @@ -335,6 +488,9 @@ export const getNote = async id => { return undefined; }; +/** + * The function sends a create activity to all followers of a user. + */ export const sendCreateToFollowers = async object => { const followers = await getFollowers(); const actors = await Promise.all( @@ -353,6 +509,10 @@ export const sendCreateToFollowers = async object => { }); }; +/** + * The function sends an update to all followers by fetching their accounts and sending the update to + * their actors using ActivityPub. + */ export const sendUpdateToFollowers = async object => { const followers = await getFollowers(); const actors = await Promise.all( @@ -371,7 +531,25 @@ export const sendUpdateToFollowers = async object => { }); }; -export const createNote = async (body, cw, inReplyTo, toUser, editOf) => { +/** + * The `createNote` function is used to create a new note or update an existing note, with options for + * specifying recipients, mentions, and content processing. + * @param body - The content of the note. + * @param cw - The `cw` parameter is a string that represents the content warning for the note. It is + * an optional parameter and can be used to provide a warning or spoiler for the content of the note. + * @param inReplyTo - The `inReplyTo` parameter is the URL of the post that the new note is replying + * to. It is used to indicate that the new note is a reply to an existing post. + * @param toUser - The `toUser` parameter is used to specify the recipient of the note. It should be a + * valid account identifier. If provided, the note will be sent directly to the specified user. + * @param editOf - The `editOf` parameter is a string that represents the URL of the post that is being + * edited. If this parameter is provided, the function will use the same GUID (Globally Unique + * Identifier) as the post being edited. + * @param canReply - Whether this note can be replied. + * @param canBoost - Whether this note can be boosted. + * @param canFave - Whether this note can be liked. + * @returns the `object` variable. + */ +export const createNote = async (body, cw, inReplyTo, toUser, editOf, canReply, canBoost, canFave) => { const publicAddress = 'https://www.w3.org/ns/activitystreams#Public'; const d = new Date(); @@ -396,7 +574,6 @@ export const createNote = async (body, cw, inReplyTo, toUser, editOf) => { if (inReplyTo || toUser) { if (toUser) { - // TODO: validate the to field is a legit account to = [toUser]; cc = []; directMessage = true; @@ -483,6 +660,9 @@ export const createNote = async (body, cw, inReplyTo, toUser, editOf) => { url, to, cc, + canReply, + canBoost, + canFave, directMessage, sensitive: !!cw, atomUri: activityId, @@ -549,6 +729,10 @@ export const createNote = async (body, cw, inReplyTo, toUser, editOf) => { return object; }; +/** + * The `follow` function follows a user, fetches their outbox, and logs any new posts to an activity + * feed. + */ export const follow = async request => { logger('following someone'); const { actor } = await fetchUser(request.object.object); @@ -582,8 +766,6 @@ export const follow = async request => { } else { createActivity(activity.object); } - } else if (activity.type === 'Announce') { - // TODO: fetch boosted posts, etc. } }); }); @@ -593,6 +775,10 @@ export const follow = async request => { } }; +/** + * The function adds a follower by fetching the user, checking if the user is already a follower, and + * then adding the user as a follower if they are not already. + */ export const addFollower = async request => { logger('Adding follower...'); const { actor } = await fetchUser(request.actor); @@ -608,6 +794,9 @@ export const addFollower = async request => { } }; +/** + * The function removes a follower by fetching the user and updating the list of followers. + */ export const removeFollower = async follower => { logger('Removing follower...'); const { actor } = await fetchUser(follower); @@ -619,7 +808,16 @@ export const removeFollower = async follower => { } }; +/** + * The `ensureAccount` function ensures that an account exists by verifying the domain name and + * generating a crypto key if the account file does not exist. + * @param name - The name parameter is a string that represents the name of the account. + * @param domain - The `domain` parameter is a string that represents the domain name. It is used to + * verify if the domain name is well-formatted before proceeding with the account creation process. + * @returns The function `ensureAccount` returns a Promise that resolves to an account object. + */ export const ensureAccount = async (name, domain) => { + console.log('Ensuring account for', name, domain); // verify domain name const re = /^((?:(?:(?:\w[.\-+]?)*)\w)+)((?:(?:(?:\w[.\-+]?){0,62})\w)+)\.(\w{2,6})$/; if (!domain.match(re)) { @@ -670,6 +868,68 @@ export const ensureAccount = async (name, domain) => { }); }; +/** + * The function checks if an account file exists and returns true if it does, otherwise it returns + * false. + * @returns a boolean value. It returns true if the accountFile exists, and false if it does not exist. + */ +export const ifAccount = () => { + if (existsSync(accountFile)) { + return true; + } + return false; +}; + +export const updateAccount = async (name, domain, bio, img) => { + // verify domain name + const re = /^((?:(?:(?:\w[.\-+]?)*)\w)+)((?:(?:(?:\w[.\-+]?){0,62})\w)+)\.(\w{2,6})$/; + if (!domain.match(re)) { + console.error('DOMAIN setting "' + domain + '" does not appear to be a well-formatted domain name.'); + process.exit(1); + } + return new Promise((resolve, reject) => { + // generate a crypto key + crypto.generateKeyPair( + 'rsa', + { + modulusLength: 4096, + publicKeyEncoding: { + type: 'spki', + format: 'pem' + }, + privateKeyEncoding: { + type: 'pkcs8', + format: 'pem' + } + }, + (err, publicKey, privateKey) => { + if (err) { + console.error(err); + reject(err); + } + const actorRecord = createActor(name, domain, publicKey, bio, img); + const webfingerRecord = createWebfinger(name, domain); + const apikey = crypto.randomBytes(16).toString('hex'); + const account = { + actor: actorRecord, + webfinger: webfingerRecord, + apikey, + publicKey, + privateKey + }; + console.log('Account created! Wrote webfinger and actor record to', accountFile); + writeJSONDictionary(accountFile, account); + resolve(account); + } + ); + }); +}; +/** + * The function `getAccount` reads a JSON dictionary from a file and returns it, or an empty object if + * the file does not exist. + * @returns The function `getAccount` is returning the result of calling the `readJSONDictionary` + * function with the `accountFile` and an empty object as arguments. + */ export const getAccount = () => { return readJSONDictionary(accountFile, {}); }; diff --git a/lib/authentication.js b/lib/authentication.js new file mode 100644 index 00000000..4f77512c --- /dev/null +++ b/lib/authentication.js @@ -0,0 +1,129 @@ +import dotenv from 'dotenv'; +import { ensureAccount, getAccount } from './account.js'; +import { promises as fsPromises } from 'fs'; +import { ActivityPub } from './ActivityPub.js'; + +/** + * The function `getUsername` retrieves the value of the `USER_NAME` environment variable. + * @returns The function `getUsername` is returning the value of the `USER_NAME` environment variable. + */ +const getUsername = () => { + dotenv.config(); + const { USER_NAME } = process.env; + return USER_NAME; +}; + +/** + * The function `getPassword` retrieves the value of the `PASS` environment variable using the `dotenv` + * package. + * @returns The function `getPassword` is returning the value of the `PASS` environment variable. + */ +const getPassword = () => { + dotenv.config(); + const { PASS } = process.env; + return PASS; +}; + +/** + * The function `authenticateLogin` checks if the provided username and password match the stored + * username and password. + * @param username - The `username` parameter is the username entered by the user during the login + * process. + * @param password - The `password` parameter is the password entered by the user during the login + * process. + * @returns a boolean value. It returns true if the provided username and password match the stored + * username and password, and false otherwise. + */ +export const authenticateLogin = (username, password) => { + if (username === getUsername() && password === getPassword()) { + return true; + } + return false; +}; + +/** + * The `createAccount` function creates a new account, sets the account in the app, sets a token in a + * cookie, and redirects to a private route. + * @param req - The `req` parameter is an object that represents the HTTP request made by the client. + * It contains information such as the request headers, request body, request method, request URL, and + * other relevant details. + * @param res - The `res` parameter is the response object that is used to send the response back to + * the client. It contains methods and properties that allow you to control the response, such as + * setting headers, sending data, and redirecting the client to a different URL. + */ +export const createAccount = async (req, res) => { + const { username, domain } = req.body; + + try { + await ensureAccount(username, domain); + + // Set account in the app + const myaccount = await getAccount(); + req.app.set('account', myaccount); + + // Set token in cookie + res.cookie('token', myaccount.apikey); + + // Redirect to private route + res.redirect('/private'); + } catch (error) { + console.error('Error creating account:', error); + res.status(500).send('Internal Server Error'); + } +}; + +/** + * The function `writeEnvToFile` writes the values of `username`, `password`, and `domain` to a `.env` + * file. + * @param req - The `req` parameter is an object that represents the HTTP request made to the server. + * It contains information about the request, such as the request method, headers, and body. + * @param res - The `res` parameter is the response object. It is used to send a response back to the + * client after the operation is completed. + */ +export const writeEnvToFile = async (req, res) => { + const { username, password, domain } = req.body; + + const envData = ` + USER_NAME=${username} + PASS=${password} + DOMAIN=${domain} + `; + + const envFilePath = './.env'; + + try { + await fsPromises.writeFile(envFilePath, envData); + console.log('Data has been written to .env file'); + } catch (error) { + console.error('Error writing to .env file:', error); + } +}; + +/** + * The function checks if the user is authenticated by comparing the token in the request cookies with + * the API key stored in the account, and redirects to the login page if not authenticated. + * @param req - The `req` parameter is the request object, which contains information about the + * incoming HTTP request from the client. It includes properties such as the request headers, query + * parameters, request body, cookies, etc. + * @param res - The `res` parameter is the response object that is used to send a response back to the + * client. It contains methods and properties that allow you to control the response, such as setting + * headers, sending data, and redirecting the client to a different URL. + * @param next - The `next` parameter is a function that is used to pass control to the next middleware + * function in the request-response cycle. It is typically called at the end of the current middleware + * function to indicate that it has completed its processing and the next middleware function should be + * called. + * @returns If the condition `req.cookies.token && req.cookies.token === myaccount.apikey` is true, + * then the `next()` function will be called, which means the control will be passed to the next + * middleware function in the request-response cycle. + */ +export const handleAuthenticatedUser = (req, res, next) => { + const myaccount = getAccount(); + req.app.set('account', myaccount); + ActivityPub.account = myaccount; + + if (req.cookies.token && req.cookies.token === myaccount.apikey) { + return next(); + } else { + res.redirect('/account/login'); + } +}; diff --git a/lib/notes.js b/lib/notes.js index af733f3f..06da6cde 100644 --- a/lib/notes.js +++ b/lib/notes.js @@ -18,6 +18,12 @@ import { ActivityPub } from './ActivityPub.js'; const logger = debug('ono:notes'); +/** + * The function `getLikesForNote` retrieves the likes and boosts for a given note ID from a JSON + * dictionary. + * @returns The function `getLikesForNote` is returning the result of calling the `readJSONDictionary` + * function with the `fileName` and an object containing `likes` and `boosts` properties. + */ export const getLikesForNote = id => { const fileName = getLikesFileName(id); return readJSONDictionary(fileName, { @@ -26,10 +32,18 @@ export const getLikesForNote = id => { }); }; +/** + * The function `getReplyCountForNote` returns the number of replies for a given note ID. + * @returns The number of replies for a given note ID. + */ export const getReplyCountForNote = id => { return INDEX.filter(i => i.inReplyTo === id).length; }; +/** + * The function records a like for a note and adds the actor to the list of likes if they haven't + * already liked the note. + */ export const recordLike = request => { const actor = request.actor; const noteId = request.object; @@ -45,6 +59,10 @@ export const recordLike = request => { } }; +/** + * The function `recordBoost` records a boost for a note and adds the actor to the list of boosts if + * they haven't already boosted the note. + */ export const recordBoost = request => { const actor = request.actor; const noteId = request.object; @@ -60,11 +78,15 @@ export const recordBoost = request => { } }; +/** + * The function `recordUndoLike` removes the actor's like from the likes list for a given note and + * updates the likes file. + */ export const recordUndoLike = request => { const actor = request.actor; const noteId = request.object; - logger('INCOMING LIKE FOR', noteId); + logger('INCOMING UNLIKE FOR', noteId); const likes = getLikesForNote(noteId); likes.likes = likes.likes.filter(a => a !== actor); @@ -72,6 +94,13 @@ export const recordUndoLike = request => { writeJSONDictionary(fileName, likes); }; +/** + * The `deleteActivity` function deletes an activity and its associated notifications from the system. + * @param id - The `id` parameter represents the unique identifier of the activity that needs to be + * deleted. It is used to locate the corresponding note file and delete it. + * @param tombstone - The `tombstone` parameter is not used in the code snippet provided. It is + * mentioned in a comment, but there is no code that utilizes it. + */ export const deleteActivity = (id, tombstone) => { const noteFile = getFileName(id); if (fs.existsSync(noteFile)) { @@ -93,6 +122,10 @@ export const deleteActivity = (id, tombstone) => { } }; +/** + * The `createActivity` function creates a new activity by writing a note to a file and adding it to an + * index if the file does not already exist. + */ export const createActivity = note => { const noteFile = createFileName(note); if (!fs.existsSync(noteFile)) { @@ -101,6 +134,12 @@ export const createActivity = note => { writeJSONDictionary(noteFile, note); }; +/** + * The function `getActivity` retrieves activity data either from a cache or by fetching it from a + * remote source, handling potential errors along the way. + * @returns The function `getActivity` returns a Promise that resolves to the result of either + * `readJSONDictionary(noteFile, {})` or `fetchActivity(id)`. + */ export const getActivity = async id => { try { if (isBlocked(id)) { @@ -110,7 +149,6 @@ export const getActivity = async id => { if (indexed !== false) { // if is cached, no need to check for file if (indexed.type === 'fail') { - // TODO: could retry after a while... throw new Error('Activity was unreachable', indexed); } else { const noteFile = getFileName(id); @@ -125,6 +163,10 @@ export const getActivity = async id => { } }; +/** + * The function fetches an activity using its ID and handles any errors that occur during the process. + * @returns The `fetchActivity` function returns the `activity` object if the fetch is successful. + */ const fetchActivity = async activityId => { logger('FETCH ', activityId); try { diff --git a/lib/prefs.js b/lib/prefs.js index 117f6840..4ae356ba 100644 --- a/lib/prefs.js +++ b/lib/prefs.js @@ -1,15 +1,17 @@ +/* The code is defining a constant variable named `DEFAULT_SETTINGS` that is exported from the module. +It is an object with two properties: `strings` and `icons`. */ export const DEFAULT_SETTINGS = { strings: { post: 'Compose' }, icons: { mascot: '🚀', - latest: '🤘🏼', - notifications: '🍑', + latest: '🆕', + notifications: '🔔', prefs: '⚙️', messages: '💬', - post: '🆕', - myPosts: '🐐', + post: '✉️', + myPosts: '📝', faveInactive: '☆', faveActive: '⭐️', boostInactive: '🔁', diff --git a/lib/queue.js b/lib/queue.js index de8bd440..8f8ee77d 100644 --- a/lib/queue.js +++ b/lib/queue.js @@ -10,8 +10,6 @@ const logger = debug('ono:queue'); export const queue = new Queue({ concurrent: 4, interval: 250 - // concurrent: 1, - // interval: 2000 }); queue.on('start', () => logger('QUEUE STARTING')); @@ -19,6 +17,9 @@ queue.on('stop', () => logger('QUEUE STOPPING')); queue.on('end', () => logger('QUEUE ENDING')); queue.on('dequeue', () => logger('DEQUEUING!', queue.size)); +/* The code block you provided is setting up event listeners for the `resolve` and `reject` events of +the `queue` object, and then starting a loop that continuously dequeues items from the queue until +`queue.shouldRun` is false. */ queue.on('resolve', data => { if (data.url) { logger(`SEND STATUS ${data.status} ${data.statusText} FOR ${data.url} `); @@ -30,7 +31,9 @@ queue.on('reject', error => console.error(error)); while (queue.shouldRun) { try { - await queue.dequeue(); + (async () => { + await queue.dequeue(); + })(); } catch (err) { console.error(err); } diff --git a/lib/storage.js b/lib/storage.js index d6bb6392..393e79a0 100644 --- a/lib/storage.js +++ b/lib/storage.js @@ -5,8 +5,8 @@ import md5 from 'md5'; import { DEFAULT_SETTINGS } from './prefs.js'; import debug from 'debug'; - import dotenv from 'dotenv'; + const logger = debug('ono:storage'); dotenv.config(); @@ -29,34 +29,71 @@ const { DOMAIN } = process.env; export const INDEX = []; export const CACHE = {}; + const cacheMax = 60 * 5 * 1000; // 5 minutes -const cacheMin = 30 * 1000; // 5 minutes +const cacheMin = 30 * 1000; // 30 seconds +/** + * Function to zero-pad a number. + * @param {number} num - The number to zero-pad. + * @returns {string} - The zero-padded number as a string. + */ const zeroPad = num => { if (num < 10) { return `0${num}`; } else return num; }; +/** + * Checks if an activity belongs to the current user. + * @param {string} activityId - The ID of the activity. + * @returns {boolean} - True if the activity belongs to the current user, false otherwise. + */ export const isMyPost = activityId => { return activityId.startsWith(`https://${DOMAIN}/m/`); }; +/** + * Checks if an activity is in the INDEX array. + * @param {string} id - The ID of the activity. + * @returns {boolean} - True if the activity is indexed, false otherwise. + */ export const isIndexed = id => { return INDEX.some(p => id === p.id); }; +/** + * Retrieves activity info from the index based on the activity ID. + * @param {string} id - The ID of the activity. + * @returns {Object|boolean} - The activity information if found, otherwise false. + */ export const fromIndex = id => { return INDEX.find(p => id === p.id) || false; }; +/** + * Gets user preferences. + * @returns {Object} - User preferences. + */ export const getPrefs = () => { return readJSONDictionary(prefsFile, DEFAULT_SETTINGS); }; + +/** + * Updates user preferences. + * @param {Object} prefs - The new user preferences. + * @returns {void} + */ export const updatePrefs = prefs => { return writeJSONDictionary(prefsFile, prefs); }; +/** + * Adds a failure entry to the index. + * @param {Object} note - The note object. + * @param {string} type - The type of failure (default is 'fail'). + * @returns {void} + */ export const addFailureToIndex = (note, type = 'fail') => { INDEX.push({ type, @@ -65,6 +102,13 @@ export const addFailureToIndex = (note, type = 'fail') => { status: note.status }); }; + +/** + * Adds an activity entry to the index. + * @param {Object} note - The note object. + * @param {string} type - The type of activity (default is 'activity'). + * @returns {void} + */ export const addActivityToIndex = (note, type = 'activity') => { INDEX.push({ type, @@ -74,6 +118,12 @@ export const addActivityToIndex = (note, type = 'activity') => { inReplyTo: note.inReplyTo }); }; + +/** + * Deletes an activity entry from the index. + * @param {string} id - The ID of the activity to be deleted. + * @returns {void} + */ export const deleteActivityFromIndex = id => { const n = INDEX.findIndex(idx => idx.id === id); if (n >= 0) { @@ -81,8 +131,12 @@ export const deleteActivityFromIndex = id => { } }; +/** + * Gets the file name for a given activity ID. + * @param {string} activityId - The ID of the activity. + * @returns {string} - The file name. + */ export const getFileName = activityId => { - // // find the item in the index // first check cache! let meta; if (CACHE[activityId]) { @@ -103,8 +157,12 @@ export const getFileName = activityId => { return path.resolve(rootPath, folder, `${md5(meta.id)}.json`); }; +/** + * Gets the file name for the likes associated with a given activity ID. + * @param {string} activityId - The ID of the activity. + * @returns {string} - The file name for likes. + */ export const getLikesFileName = activityId => { - // // find the item in the index // first check cache! let meta; if (CACHE[activityId]) { @@ -125,6 +183,11 @@ export const getLikesFileName = activityId => { return path.resolve(rootPath, folder, `${md5(meta.id)}.likes.json`); }; +/** + * Creates a file name for a given activity. + * @param {Object} activity - The activity object. + * @returns {string} - The file name. + */ export const createFileName = activity => { // create a dated subfolder const datestamp = new Date(activity.published); @@ -140,6 +203,10 @@ export const createFileName = activity => { return path.resolve(rootPath, folder, `${md5(activity.id)}.json`); }; +/** + * Clears expired entries from the cache. + * @returns {void} + */ const cacheExpire = () => { const now = new Date().getTime(); for (const key in CACHE) { @@ -150,12 +217,20 @@ const cacheExpire = () => { } }; +/** + * Interval function for the garbage collector to clear expired cache entries. + * @type {number} + */ const garbageCollector = setInterval(() => { cacheExpire(); }, cacheMin); logger('Garbage collector interval', garbageCollector); +/** + * Builds the initial index by reading data from files. + * @returns {Promise>} - A promise that resolves with the built index. + */ const buildIndex = () => { return new Promise((resolve, reject) => { glob(path.join(pathToFiles, '**/*.json'), async (err, files) => { @@ -163,7 +238,7 @@ const buildIndex = () => { console.error(err); reject(err); } - // const res = []; + for (const f of files) { try { const post = JSON.parse(fs.readFileSync(path.resolve(pathToFiles, f))); @@ -198,6 +273,11 @@ const buildIndex = () => { }); }; +/** + * Searches for known users based on a query string. + * @param {string} query - The search query. + * @returns {Promise>} - A promise that resolves with the search results. + */ export const searchKnownUsers = async query => { return new Promise((resolve, reject) => { glob(path.join(pathToUsers, '**/*.json'), async (err, files) => { @@ -227,6 +307,10 @@ export const searchKnownUsers = async query => { }); }; +/** + * Ensures the existence of data folders and default settings. + * @returns {void} + */ const ensureDataFolder = () => { if (!fs.existsSync(path.resolve(pathToPosts))) { logger('mkdir', pathToPosts); @@ -255,11 +339,15 @@ const ensureDataFolder = () => { if (!fs.existsSync(path.resolve(prefsFile))) { logger('create default settings', prefsFile); writeJSONDictionary(prefsFile, DEFAULT_SETTINGS); - } else { - // todo: validate settings, add any missing keys with default values } }; +/** + * Reads a JSON dictionary from a file path. + * @param {string} path - The path to the JSON file. + * @param {Array} defaultVal - The default value if the file doesn't exist. + * @returns {Array} - The contents of the JSON file. + */ export const readJSONDictionary = (path, defaultVal = []) => { const now = new Date().getTime(); if (CACHE[path] && CACHE[path].time > now - cacheMax) { @@ -282,11 +370,22 @@ export const readJSONDictionary = (path, defaultVal = []) => { } }; +/** + * Deletes a JSON dictionary file. + * @param {string} path - The path to the JSON file to be deleted. + * @returns {void} + */ export const deleteJSONDictionary = path => { fs.unlinkSync(path); delete CACHE[path]; }; +/** + * Writes a JSON dictionary to a file. + * @param {string} path - The path to the file. + * @param {Object} data - The data to be written. + * @returns {void} + */ export const writeJSONDictionary = (path, data) => { const now = new Date().getTime(); logger('write cache', path); diff --git a/lib/theAlgorithm.js b/lib/theAlgorithm.js index cd5bd4e8..099857c1 100644 --- a/lib/theAlgorithm.js +++ b/lib/theAlgorithm.js @@ -27,6 +27,14 @@ import { ActivityPub } from './ActivityPub.js'; const logger = debug('ono:algorithm'); +/** + * The function `sortByDate` takes two values and compares them. It is used to sort posts in reverse + * order. + * @param a - The first object being compared. + * @param b - The parameter `b` represents the second item being compared in the `sortByDate` function. + * @returns The `sortByDate` function returns -1 if `a.published` is greater than `b.published`, 1 if + * `a.published` is less than `b.published`, and 0 if `a.published` is equal to `b.published`. + */ export const sortByDate = (a, b) => { if (a.published > b.published) { return -1; @@ -84,10 +92,23 @@ export const getFullPostDetails = async activityOrId => { note, actor, boost, + booster }; }; +/** + * The `getActivityStream` function generates an activity stream by sorting and filtering posts, and + * then iterating over them to retrieve the necessary details. + * @param limit - The `limit` parameter specifies the maximum number of posts to include in the + * activity stream. It determines how many posts will be returned in the `activitystream` array. + * @param offset - The `offset` parameter is used to determine the starting point of the activity + * stream. It specifies the index position in the `sortedSlice` array from where the iteration should + * begin. + * @returns an object with two properties: "activitystream" and "next". The "activitystream" property + * contains an array of posts, and the "next" property contains the index of the next post to be + * fetched. + */ export const getActivityStream = async (limit, offset) => { logger('Generating activity stream...'); @@ -100,20 +121,20 @@ export const getActivityStream = async (limit, offset) => { const stream = []; // iterate over the list until we get enough posts (or run out of posts) - let px; - for (px = offset; px < sortedSlice.length; px++) { - const p = sortedSlice[px]; + let postIndex; + for (postIndex = offset; postIndex < sortedSlice.length; postIndex++) { + const postObject = sortedSlice[postIndex]; // process a post by someone else - if (p.type === 'activity') { + if (postObject.type === 'activity') { // Ignore posts from people I am not following - if (!isFollowing(p.actor)) { + if (!isFollowing(postObject.actor)) { continue; } - if (!p.inReplyTo || isReplyToMyPost(p) || (await isReplyToFollowing(p))) { + if (!postObject.inReplyTo || isReplyToMyPost(postObject) || (await isReplyToFollowing(postObject))) { try { - const post = await getFullPostDetails(p.id); + const post = await getFullPostDetails(postObject.id); stream.push(post); } catch (err) { console.error('error while loading post from index'); @@ -124,8 +145,8 @@ export const getActivityStream = async (limit, offset) => { } // process a post by me - if (p.type === 'note') { - const post = await getFullPostDetails(p.id); + if (postObject.type === 'note') { + const post = await getFullPostDetails(postObject.id); stream.push(post); } @@ -137,10 +158,24 @@ export const getActivityStream = async (limit, offset) => { return { activitystream: stream, - next: px + next: postIndex }; }; +/** + * The function `getActivitySince` retrieves activity data since a specified date, excluding the user's + * own activity if specified. + * @param since - The `since` parameter is a timestamp indicating the starting point from which you + * want to retrieve activity. Only activities that occurred after this timestamp will be included in + * the result. + * @param [excludeSelf=false] - The `excludeSelf` parameter is a boolean flag that determines whether + * or not to exclude the posts made by the current user (self) from the result. If `excludeSelf` is set + * to `true`, the posts made by the current user will be filtered out from the result. If `exclude + * @returns an object with a property called "activitystream" which contains an array of objects. Each + * object in the array represents an activity or a note. Each object has two properties: "note" which + * represents the content of the activity or note, and "actor" which represents the actor who performed + * the activity or created the note. + */ export const getActivitySince = async (since, excludeSelf = false) => { // sort all known posts by date quickly const sortedSlice = INDEX.filter(p => p.type !== 'fail' && !isNaN(p.published)) @@ -152,17 +187,17 @@ export const getActivitySince = async (since, excludeSelf = false) => { return p.published > since; }); - const res = []; - let px; - for (px = 0; px < sortedSlice.length; px++) { - const p = sortedSlice[px]; - if (p.type === 'activity') { - if (isFollowing(p.actor)) { - if (!p.inReplyTo || isReplyToMyPost(p) || (await isReplyToFollowing(p))) { + const stream = []; + let postIndex; + for (postIndex = 0; postIndex < sortedSlice.length; postIndex++) { + const postObject = sortedSlice[postIndex]; + if (postObject.type === 'activity') { + if (isFollowing(postObject.actor)) { + if (!postObject.inReplyTo || isReplyToMyPost(postObject) || (await isReplyToFollowing(postObject))) { try { - const { actor } = await fetchUser(p.actor); - const post = await getActivity(p.id); - res.push({ + const { actor } = await fetchUser(postObject.actor); + const post = await getActivity(postObject.id); + stream.push({ note: post, actor }); @@ -176,8 +211,8 @@ export const getActivitySince = async (since, excludeSelf = false) => { // disregard not from following } } else { - const post = await getNote(p.id); - res.push({ + const post = await getNote(postObject.id); + stream.push({ note: post, actor: ActivityPub.actor }); @@ -185,6 +220,6 @@ export const getActivitySince = async (since, excludeSelf = false) => { } return { - activitystream: res + activitystream: stream }; }; diff --git a/lib/users.js b/lib/users.js index f40ffce4..8ebe9fa6 100644 --- a/lib/users.js +++ b/lib/users.js @@ -1,11 +1,23 @@ import path from 'path'; import fs from 'fs'; import debug from 'debug'; - import { readJSONDictionary, writeJSONDictionary, pathToUsers } from './storage.js'; import { ActivityPub } from './ActivityPub.js'; + const logger = debug('ono:users'); +/** + * The function `fetchUserFromSource` fetches user information from a given webId or username using the + * ActivityPub protocol. + * @param username - The `username` parameter is the username of the user you want to fetch from the + * source. It is used to identify the user and retrieve their information. + * @param webId - The `webId` parameter is a string that represents the unique identifier of a user on + * the web. It is used to fetch the actor information of the user from an ActivityPub server. If the + * `webId` parameter is not provided, the function will attempt to fetch the actor information using + * the + * @returns The function `fetchUserFromSource` returns an object with the properties `webfinger`, + * `actor`, and `lastFetched`. + */ const fetchUserFromSource = async (username, webId) => { let webfinger; @@ -13,7 +25,6 @@ const fetchUserFromSource = async (username, webId) => { try { webfinger = await ActivityPub.webfinger(username); } catch (err) { - // console.error(err); // servers receive lots of spam Deletes return { actor: { name: username, @@ -31,7 +42,6 @@ const fetchUserFromSource = async (username, webId) => { try { actor = await ActivityPub.fetchActor(self); } catch (err) { - // console.error(err); return { actor: { name: username, @@ -59,6 +69,11 @@ const fetchUserFromSource = async (username, webId) => { }; }; +/** + * The `fetchUser` function fetches user information either from a cache or from a source, with an + * option to skip fingerprinting if the user is already an ActivityPub URL. + * @returns The function `fetchUser` returns a Promise that resolves to the user account information. + */ export const fetchUser = async user => { let skipFinger = false; const now = new Date().getTime(); @@ -84,7 +99,6 @@ export const fetchUser = async user => { } else { logger('fetch fresh user for', user, `${username}`); // attempt to fetch a new one async - // TODO: needs to be debounced - could try to load same user many times quickly fetchUserFromSource(username, account?.actor?.id).catch(err => console.error('Error updating user data for', username, err) ); diff --git a/package-lock.json b/package-lock.json index 4407a6b9..e236573f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "cors": "^2.8.4", "debug": "^4.3.4", "dotenv": "^16.0.3", - "express": "^4.16.3", + "express": "^4.18.2", "express-basic-auth": "^1.1.5", "express-handlebars": "^6.0.6", "glob": "^8.0.3", @@ -24,2933 +24,3638 @@ "markdown-it": "^13.0.1", "md5": "^2.3.0", "moment": "^2.29.4", + "multer": "^1.4.5-lts.1", "node-fetch": "^3.3.0", + "nodemon": "^3.0.2", "queue-promise": "^2.2.1", "rss-generator": "^0.0.3" }, "devDependencies": { + "@babel/core": "^7.23.3", + "@babel/preset-env": "^7.23.3", + "babel-jest": "^29.7.0", "eslint": "^8.32.0", "eslint-config-prettier": "^8.6.0", "eslint-config-standard": "^17.0.0", "eslint-plugin-import": "^2.27.5", "eslint-plugin-n": "^15.6.1", "eslint-plugin-promise": "^6.1.1", - "lint-staged": "^13.1.0", + "jest": "^29.7.0", + "lint-staged": "^13.2.3", "prettier": "^2.8.3" }, "engines": { "node": "16.x" } }, - "node_modules/@eslint/eslintrc": { - "version": "1.4.1", + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", "dev": true, - "license": "MIT", "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.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" + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=6.0.0" } }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", + "node_modules/@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, - "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", + "node_modules/@babel/code-frame/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, - "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "color-convert": "^1.9.0" }, "engines": { - "node": "*" + "node": ">=4" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", + "node_modules/@babel/code-frame/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, - "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "engines": { - "node": ">=10.10.0" + "node": ">=4" } }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.11", + "node_modules/@babel/code-frame/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, - "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "color-name": "1.1.3" } }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", + "node_modules/@babel/code-frame/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/code-frame/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==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame/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, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/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, - "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "has-flag": "^3.0.0" }, "engines": { - "node": "*" + "node": ">=4" } }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", + "node_modules/@babel/compat-data": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.3.tgz", + "integrity": "sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==", "dev": true, - "license": "Apache-2.0", "engines": { - "node": ">=12.22" + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.3.tgz", + "integrity": "sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.3", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.2", + "@babel/parser": "^7.23.3", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.3", + "@babel/types": "^7.23.3", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", + "node_modules/@babel/core/node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, - "license": "BSD-3-Clause" + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", + "node_modules/@babel/generator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.3.tgz", + "integrity": "sha512-keeZWAV4LU3tW0qRi19HRpabC/ilM0HRBBzf9/k8FFiG4KVpiv0FIy4hHfLfFQZNhziCTPTmd59zoyv6DNISzg==", "dev": true, - "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "@babel/types": "^7.23.3", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" }, "engines": { - "node": ">= 8" + "node": ">=6.9.0" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", + "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, - "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, "engines": { - "node": ">= 8" + "node": ">=6.9.0" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", + "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, - "license": "MIT", "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "@babel/types": "^7.22.15" }, "engines": { - "node": ">= 8" + "node": ">=6.9.0" } }, - "node_modules/@types/json5": { - "version": "0.0.29", + "node_modules/@babel/helper-compilation-targets": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", "dev": true, - "license": "MIT" - }, - "node_modules/accepts": { - "version": "1.3.8", - "license": "MIT", "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" }, "engines": { - "node": ">= 0.6" + "node": ">=6.9.0" } }, - "node_modules/acorn": { - "version": "8.8.1", + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.15.tgz", + "integrity": "sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" }, "engines": { - "node": ">=0.4.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/acorn-jsx": { - "version": "5.3.2", + "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, - "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@babel/core": "^7.0.0" } }, - "node_modules/aggregate-error": { - "version": "3.1.0", + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.3.tgz", + "integrity": "sha512-WBrLmuPP47n7PNwsZ57pqam6G/RGo1vw/87b0Blc53tZNGZ4x7YvZ6HgQe2vo1W/FR20OgjeZuGXzudPiXHFug==", "dev": true, - "license": "MIT", "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.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.4.0 || ^8.0.0-0 <8.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, "engines": { - "node": ">=8" + "node": ">=6.9.0" } }, - "node_modules/ajv": { - "version": "6.12.6", + "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, - "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" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/ansi-escapes": { - "version": "4.3.2", + "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, - "license": "MIT", "dependencies": { - "type-fest": "^0.21.3" + "@babel/types": "^7.22.5" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6.9.0" } }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", + "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, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" + "dependencies": { + "@babel/types": "^7.23.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", "dev": true, - "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.15" + }, "engines": { - "node": ">=8" + "node": ">=6.9.0" } }, - "node_modules/ansi-styles": { - "version": "4.3.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, - "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "@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": ">=8" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/argparse": { - "version": "2.0.1", - "license": "Python-2.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, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/array-flatten": { - "version": "1.1.1", - "license": "MIT" + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/array-includes": { - "version": "3.1.6", + "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, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "is-string": "^1.0.7" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" }, "engines": { - "node": ">= 0.4" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/array.prototype.flat": { - "version": "1.3.1", + "node_modules/@babel/helper-replace-supers": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", + "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5" }, "engines": { - "node": ">= 0.4" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.1", + "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, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" + "@babel/types": "^7.22.5" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=6.9.0" } }, - "node_modules/astral-regex": { - "version": "2.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, - "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, "engines": { - "node": ">=8" + "node": ">=6.9.0" } }, - "node_modules/available-typed-arrays": { - "version": "1.0.5", + "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, - "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "@babel/types": "^7.22.5" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/balanced-match": { - "version": "1.0.2", - "license": "MIT" - }, - "node_modules/basic-auth": { - "version": "2.0.1", - "license": "MIT", - "dependencies": { - "safe-buffer": "5.1.2" - }, + "node_modules/@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "dev": true, "engines": { - "node": ">= 0.8" + "node": ">=6.9.0" } }, - "node_modules/basic-auth/node_modules/safe-buffer": { - "version": "5.1.2", - "license": "MIT" - }, - "node_modules/body-parser": { - "version": "1.20.1", - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "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.1", - "type-is": "~1.6.18", - "unpipe": "1.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, "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "node": ">=6.9.0" } }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" + "node_modules/@babel/helper-validator-option": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", + "dev": true, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "license": "MIT" - }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "license": "MIT", + "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, "dependencies": { - "balanced-match": "^1.0.0" + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/braces": { - "version": "3.0.2", + "node_modules/@babel/helpers": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz", + "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==", "dev": true, - "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.2", + "@babel/types": "^7.23.0" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" } }, - "node_modules/builtins": { - "version": "5.0.1", + "node_modules/@babel/highlight": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, - "license": "MIT", "dependencies": { - "semver": "^7.0.0" + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/builtins/node_modules/semver": { - "version": "7.3.8", + "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, - "license": "ISC", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "color-convert": "^1.9.0" }, "engines": { - "node": ">=10" + "node": ">=4" } }, - "node_modules/bytes": { - "version": "3.1.2", - "license": "MIT", + "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, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, "engines": { - "node": ">= 0.8" + "node": ">=4" } }, - "node_modules/call-bind": { - "version": "1.0.2", - "license": "MIT", + "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, "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "color-name": "1.1.3" } }, - "node_modules/callsites": { - "version": "3.1.0", + "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/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==", "dev": true, - "license": "MIT", "engines": { - "node": ">=6" + "node": ">=0.8.0" } }, - "node_modules/chalk": { - "version": "4.1.2", + "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, - "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": ">=4" } }, - "node_modules/charenc": { - "version": "0.0.2", - "license": "BSD-3-Clause", + "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, + "dependencies": { + "has-flag": "^3.0.0" + }, "engines": { - "node": "*" + "node": ">=4" } }, - "node_modules/clean-stack": { - "version": "2.2.0", + "node_modules/@babel/parser": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.3.tgz", + "integrity": "sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==", "dev": true, - "license": "MIT", + "bin": { + "parser": "bin/babel-parser.js" + }, "engines": { - "node": ">=6" + "node": ">=6.0.0" } }, - "node_modules/cli-cursor": { - "version": "3.1.0", + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.23.3", + "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.23.3.tgz", + "integrity": "sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==", "dev": true, - "license": "MIT", "dependencies": { - "restore-cursor": "^3.1.0" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/cli-truncate": { - "version": "3.1.0", + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.23.3.tgz", + "integrity": "sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==", "dev": true, - "license": "MIT", "dependencies": { - "slice-ansi": "^5.0.0", - "string-width": "^5.0.0" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.23.3" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@babel/core": "^7.13.0" } }, - "node_modules/color-convert": { - "version": "2.0.1", + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.3.tgz", + "integrity": "sha512-XaJak1qcityzrX0/IU5nKHb34VaibwP3saKqG6a/tppelgllOH13LUann4ZCIBcVOeE6H18K4Vx9QKkVww3z/w==", "dev": true, - "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">=7.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/color-name": { - "version": "1.1.4", + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", "dev": true, - "license": "MIT" + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/colorette": { - "version": "2.0.19", + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "dev": true, - "license": "MIT" + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/commander": { - "version": "9.5.0", + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || >=14" + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/concat-map": { - "version": "0.0.1", + "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==", "dev": true, - "license": "MIT" + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/content-disposition": { - "version": "0.5.4", - "license": "MIT", + "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==", + "dev": true, "dependencies": { - "safe-buffer": "5.2.1" + "@babel/helper-plugin-utils": "^7.14.5" }, "engines": { - "node": ">= 0.6" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/content-type": { - "version": "1.0.4", - "license": "MIT", - "engines": { - "node": ">= 0.6" + "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==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/cookie": { - "version": "0.5.0", - "license": "MIT", - "engines": { - "node": ">= 0.6" + "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==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/cookie-parser": { - "version": "1.4.6", - "license": "MIT", + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.23.3.tgz", + "integrity": "sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==", + "dev": true, "dependencies": { - "cookie": "0.4.1", - "cookie-signature": "1.0.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">= 0.8.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/cookie-parser/node_modules/cookie": { - "version": "0.4.1", - "license": "MIT", + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.23.3.tgz", + "integrity": "sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, "engines": { - "node": ">= 0.6" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "license": "MIT" - }, - "node_modules/copy-env-cli": { - "version": "1.0.0", - "license": "MIT", - "bin": { - "copy-env-cli": "bin.js" + "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==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/cors": { - "version": "2.8.5", - "license": "MIT", + "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==", + "dev": true, "dependencies": { - "object-assign": "^4", - "vary": "^1" + "@babel/helper-plugin-utils": "^7.8.0" }, - "engines": { - "node": ">= 0.10" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/cross-spawn": { - "version": "7.0.3", + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", + "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", "dev": true, - "license": "MIT", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">= 8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/crypt": { - "version": "0.0.2", - "license": "BSD-3-Clause", - "engines": { - "node": "*" + "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==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.0", - "license": "MIT", - "engines": { - "node": ">= 12" + "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==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/debug": { - "version": "4.3.4", - "license": "MIT", + "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==", + "dev": true, "dependencies": { - "ms": "2.1.2" + "@babel/helper-plugin-utils": "^7.10.4" }, - "engines": { - "node": ">=6.0" + "peerDependencies": { + "@babel/core": "^7.0.0-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==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/deep-is": { - "version": "0.1.4", + "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==", "dev": true, - "license": "MIT" + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/define-properties": { - "version": "1.1.4", + "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==", "dev": true, - "license": "MIT", "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" + "@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", + "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==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" }, "engines": { - "node": ">= 0.4" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/depd": { - "version": "2.0.0", - "license": "MIT", + "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==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, "engines": { - "node": ">= 0.8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/destroy": { - "version": "1.2.0", - "license": "MIT", + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz", + "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/doctrine": { - "version": "3.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==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "esutils": "^2.0.2" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/dotenv": { - "version": "16.0.3", - "license": "BSD-2-Clause", + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz", + "integrity": "sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/eastasianwidth": { - "version": "0.2.0", + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.3.tgz", + "integrity": "sha512-59GsVNavGxAXCDDbakWSMJhajASb4kBCqDjqJsv+p5nKdbz7istmZ3HrX3L2LuiI80+zsOADCvooqQH3qGCucQ==", "dev": true, - "license": "MIT" - }, - "node_modules/ee-first": { - "version": "1.1.1", - "license": "MIT" + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/emoji-regex": { - "version": "9.2.2", + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz", + "integrity": "sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==", "dev": true, - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20" + }, "engines": { - "node": ">= 0.8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/entities": { - "version": "3.0.1", - "license": "BSD-2-Clause", + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz", + "integrity": "sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, "engines": { - "node": ">=0.12" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/es-abstract": { - "version": "1.21.1", + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.3.tgz", + "integrity": "sha512-QPZxHrThbQia7UdvfpaRRlq/J9ciz1J4go0k+lPBXbgaNeY7IQrBj/9ceWjvMMI07/ZBzHl/F0R/2K0qH7jCVw==", "dev": true, - "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.3", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.4", - "is-array-buffer": "^3.0.1", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.10", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.2", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trimend": "^1.0.6", - "string.prototype.trimstart": "^1.0.6", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.9" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">= 0.4" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/es-set-tostringtag": { - "version": "2.0.1", + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.23.3.tgz", + "integrity": "sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==", "dev": true, - "license": "MIT", "dependencies": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">= 0.4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/es-shim-unscopables": { - "version": "1.0.0", + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.23.3.tgz", + "integrity": "sha512-PENDVxdr7ZxKPyi5Ffc0LjXdnJyrJxyqF5T5YjlVg4a0VFfQHW0r8iAtRiDXkfHlu1wwcvdtnndGYIeJLSuRMQ==", "dev": true, - "license": "MIT", "dependencies": { - "has": "^1.0.3" + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" } }, - "node_modules/es-to-primitive": { - "version": "1.2.1", + "node_modules/@babel/plugin-transform-classes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.3.tgz", + "integrity": "sha512-FGEQmugvAEu2QtgtU0uTASXevfLMFfBeVCIIdcQhn/uBQsMTjBajdnAtanQlOcuihWh10PZ7+HWvc7NtBwP74w==", "dev": true, - "license": "MIT", "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" }, "engines": { - "node": ">= 0.4" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "license": "MIT" + "node_modules/@babel/plugin-transform-classes/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz", + "integrity": "sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==", "dev": true, - "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.15" + }, "engines": { - "node": ">=10" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint": { - "version": "8.32.0", + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz", + "integrity": "sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==", "dev": true, - "license": "MIT", "dependencies": { - "@eslint/eslintrc": "^1.4.1", - "@humanwhocodes/config-array": "^0.11.8", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "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.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", - "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", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "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.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=6.9.0" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-config-prettier": { - "version": "8.6.0", + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.23.3.tgz", + "integrity": "sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==", "dev": true, - "license": "MIT", - "bin": { - "eslint-config-prettier": "bin/cli.js" + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "eslint": ">=7.0.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-config-standard": { - "version": "17.0.0", + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.23.3.tgz", + "integrity": "sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==", "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": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, "peerDependencies": { - "eslint": "^8.0.1", - "eslint-plugin-import": "^2.25.2", - "eslint-plugin-n": "^15.0.0", - "eslint-plugin-promise": "^6.0.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.7", + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.23.3.tgz", + "integrity": "sha512-vTG+cTGxPFou12Rj7ll+eD5yWeNl5/8xvQvF08y5Gv3v4mZQoyFf8/n9zg4q5vvCWt5jmgymfzMAldO7orBn7A==", "dev": true, - "license": "MIT", "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.11.0", - "resolve": "^1.22.1" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz", + "integrity": "sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==", "dev": true, - "license": "MIT", "dependencies": { - "ms": "^2.1.1" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-module-utils": { - "version": "2.7.4", + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.23.3.tgz", + "integrity": "sha512-yCLhW34wpJWRdTxxWtFZASJisihrfyMOTOQexhVzA78jlU+dH7Dw+zQgcPepQ5F3C6bAIiblZZ+qBggJdHiBAg==", "dev": true, - "license": "MIT", "dependencies": { - "debug": "^3.2.7" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.3.tgz", + "integrity": "sha512-X8jSm8X1CMwxmK878qsUGJRmbysKNbdpTv/O1/v0LuY/ZkZrng5WYiekYSdg9m09OTmDDUWeEDsTE+17WYbAZw==", "dev": true, - "license": "MIT", "dependencies": { - "ms": "^2.1.1" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-plugin-es": { - "version": "4.1.0", + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.23.3.tgz", + "integrity": "sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==", "dev": true, - "license": "MIT", "dependencies": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">=8.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" + "node": ">=6.9.0" }, "peerDependencies": { - "eslint": ">=4.19.1" + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-plugin-es/node_modules/eslint-utils": { - "version": "2.1.0", + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.23.3.tgz", + "integrity": "sha512-H9Ej2OiISIZowZHaBwF0tsJOih1PftXJtE8EWqlEIwpc7LMTGq0rPOrywKLQ4nefzx8/HMR0D3JGXoMHYvhi0A==", "dev": true, - "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^1.1.0" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" }, "engines": { - "node": ">=6" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-plugin-es/node_modules/eslint-visitor-keys": { - "version": "1.3.0", + "node_modules/@babel/plugin-transform-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz", + "integrity": "sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==", "dev": true, - "license": "Apache-2.0", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-plugin-import": { - "version": "2.27.5", + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.23.3.tgz", + "integrity": "sha512-+pD5ZbxofyOygEp+zZAfujY2ShNCXRpDRIPOiBmTO693hhyOEteZgl876Xs9SAHPQpcV0vz8LvA/T+w8AzyX8A==", "dev": true, - "license": "MIT", "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "array.prototype.flatmap": "^1.3.1", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.7", - "eslint-module-utils": "^2.7.4", - "has": "^1.0.3", - "is-core-module": "^2.11.0", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.values": "^1.1.6", - "resolve": "^1.22.1", - "semver": "^6.3.0", - "tsconfig-paths": "^3.14.1" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" }, "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-plugin-import/node_modules/brace-expansion": { - "version": "1.1.11", + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.23.3.tgz", + "integrity": "sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==", "dev": true, - "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz", + "integrity": "sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==", "dev": true, - "license": "MIT", "dependencies": { - "ms": "^2.1.1" + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz", + "integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "esutils": "^2.0.2" + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" }, "engines": { - "node": ">=0.10.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-plugin-import/node_modules/minimatch": { - "version": "3.1.2", + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.3.tgz", + "integrity": "sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ==", "dev": true, - "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20" }, "engines": { - "node": "*" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-plugin-n": { - "version": "15.6.1", + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz", + "integrity": "sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==", "dev": true, - "license": "MIT", "dependencies": { - "builtins": "^5.0.1", - "eslint-plugin-es": "^4.1.0", - "eslint-utils": "^3.0.0", - "ignore": "^5.1.1", - "is-core-module": "^2.11.0", - "minimatch": "^3.1.2", - "resolve": "^1.22.1", - "semver": "^7.3.8" + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">=12.22.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" + "node": ">=6.9.0" }, "peerDependencies": { - "eslint": ">=7.0.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-plugin-n/node_modules/brace-expansion": { - "version": "1.1.11", + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", "dev": true, - "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@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/eslint-plugin-n/node_modules/minimatch": { - "version": "3.1.2", + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz", + "integrity": "sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==", "dev": true, - "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": "*" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-plugin-n/node_modules/semver": { - "version": "7.3.8", + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.23.3.tgz", + "integrity": "sha512-xzg24Lnld4DYIdysyf07zJ1P+iIfJpxtVFOzX4g+bsJ3Ng5Le7rXx9KwqKzuyaUeRnt+I1EICwQITqc0E2PmpA==", "dev": true, - "license": "ISC", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" }, "engines": { - "node": ">=10" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-plugin-promise": { - "version": "6.1.1", + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.23.3.tgz", + "integrity": "sha512-s9GO7fIBi/BLsZ0v3Rftr6Oe4t0ctJ8h4CCXfPoEJwmvAPMyNrfkOOJzm6b9PX9YXcCJWWQd/sBF/N26eBiMVw==", "dev": true, - "license": "ISC", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=6.9.0" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-scope": { - "version": "7.1.1", + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.3.tgz", + "integrity": "sha512-VxHt0ANkDmu8TANdE9Kc0rndo/ccsmfe2Cx2y5sI4hu3AukHQ5wAu4cM7j3ba8B9548ijVyclBU+nuDQftZsog==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "@babel/compat-data": "^7.23.3", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.23.3" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-utils": { - "version": "3.0.0", + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz", + "integrity": "sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==", "dev": true, - "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^2.0.0" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20" }, "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" + "node": ">=6.9.0" }, "peerDependencies": { - "eslint": ">=5" + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.23.3.tgz", + "integrity": "sha512-LxYSb0iLjUamfm7f1D7GpiS4j0UAC8AOiehnsGAP8BEsIX8EOi3qV6bbctw8M7ZvLtcoZfZX5Z7rN9PlWk0m5A==", "dev": true, - "license": "Apache-2.0", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, "engines": { - "node": ">=10" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-visitor-keys": { - "version": "3.3.0", + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.3.tgz", + "integrity": "sha512-zvL8vIfIUgMccIAK1lxjvNv572JHFJIKb4MWBz5OGdBQA0fB0Xluix5rmOby48exiJc987neOmP/m9Fnpkz3Tg==", "dev": true, - "license": "Apache-2.0", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz", + "integrity": "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==", "dev": true, - "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.23.3.tgz", + "integrity": "sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==", "dev": true, - "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": "*" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/espree": { - "version": "9.4.1", + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.3.tgz", + "integrity": "sha512-a5m2oLNFyje2e/rGKjVfAELTVI5mbA0FeZpBnkOWWV7eSmKQ+T/XW0Vf+29ScLzSxX+rnsarvU0oie/4m6hkxA==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=6.9.0" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/esquery": { - "version": "1.4.0", + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz", + "integrity": "sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { - "estraverse": "^5.1.0" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">=0.10" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/esrecurse": { - "version": "4.3.0", + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz", + "integrity": "sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "estraverse": "^5.2.0" + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.2" }, "engines": { - "node": ">=4.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/estraverse": { - "version": "5.3.0", + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz", + "integrity": "sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==", "dev": true, - "license": "BSD-2-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, "engines": { - "node": ">=4.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/esutils": { - "version": "2.0.3", + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz", + "integrity": "sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==", "dev": true, - "license": "BSD-2-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/etag": { - "version": "1.8.1", - "license": "MIT", + "node_modules/@babel/plugin-transform-spread": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz", + "integrity": "sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, "engines": { - "node": ">= 0.6" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/execa": { - "version": "6.1.0", + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz", + "integrity": "sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==", "dev": true, - "license": "MIT", "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.1", - "human-signals": "^3.0.1", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^3.0.7", - "strip-final-newline": "^3.0.0" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/express": { - "version": "4.18.2", - "license": "MIT", + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz", + "integrity": "sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==", + "dev": true, "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.1", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.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" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">= 0.10.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/express-basic-auth": { - "version": "1.2.1", - "license": "MIT", + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz", + "integrity": "sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==", + "dev": true, "dependencies": { - "basic-auth": "^2.0.1" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/express-handlebars": { - "version": "6.0.6", - "license": "BSD-3-Clause", + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz", + "integrity": "sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==", + "dev": true, "dependencies": { - "glob": "^8.0.2", - "graceful-fs": "^4.2.10", - "handlebars": "^4.7.7" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">=v12.22.9" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "license": "MIT", + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.23.3.tgz", + "integrity": "sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==", + "dev": true, "dependencies": { - "ms": "2.0.0" + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "license": "MIT" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz", + "integrity": "sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==", "dev": true, - "license": "MIT" + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.23.3.tgz", + "integrity": "sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==", "dev": true, - "license": "MIT" + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.3.tgz", + "integrity": "sha512-ovzGc2uuyNfNAs/jyjIGxS8arOHS5FENZaNn4rtE7UdKMMkqHCvboHfcuhWLZNX5cB44QfcGNWjaevxMzzMf+Q==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.3", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.3", + "@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.23.3", + "@babel/plugin-syntax-import-attributes": "^7.23.3", + "@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.23.3", + "@babel/plugin-transform-async-generator-functions": "^7.23.3", + "@babel/plugin-transform-async-to-generator": "^7.23.3", + "@babel/plugin-transform-block-scoped-functions": "^7.23.3", + "@babel/plugin-transform-block-scoping": "^7.23.3", + "@babel/plugin-transform-class-properties": "^7.23.3", + "@babel/plugin-transform-class-static-block": "^7.23.3", + "@babel/plugin-transform-classes": "^7.23.3", + "@babel/plugin-transform-computed-properties": "^7.23.3", + "@babel/plugin-transform-destructuring": "^7.23.3", + "@babel/plugin-transform-dotall-regex": "^7.23.3", + "@babel/plugin-transform-duplicate-keys": "^7.23.3", + "@babel/plugin-transform-dynamic-import": "^7.23.3", + "@babel/plugin-transform-exponentiation-operator": "^7.23.3", + "@babel/plugin-transform-export-namespace-from": "^7.23.3", + "@babel/plugin-transform-for-of": "^7.23.3", + "@babel/plugin-transform-function-name": "^7.23.3", + "@babel/plugin-transform-json-strings": "^7.23.3", + "@babel/plugin-transform-literals": "^7.23.3", + "@babel/plugin-transform-logical-assignment-operators": "^7.23.3", + "@babel/plugin-transform-member-expression-literals": "^7.23.3", + "@babel/plugin-transform-modules-amd": "^7.23.3", + "@babel/plugin-transform-modules-commonjs": "^7.23.3", + "@babel/plugin-transform-modules-systemjs": "^7.23.3", + "@babel/plugin-transform-modules-umd": "^7.23.3", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.23.3", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.23.3", + "@babel/plugin-transform-numeric-separator": "^7.23.3", + "@babel/plugin-transform-object-rest-spread": "^7.23.3", + "@babel/plugin-transform-object-super": "^7.23.3", + "@babel/plugin-transform-optional-catch-binding": "^7.23.3", + "@babel/plugin-transform-optional-chaining": "^7.23.3", + "@babel/plugin-transform-parameters": "^7.23.3", + "@babel/plugin-transform-private-methods": "^7.23.3", + "@babel/plugin-transform-private-property-in-object": "^7.23.3", + "@babel/plugin-transform-property-literals": "^7.23.3", + "@babel/plugin-transform-regenerator": "^7.23.3", + "@babel/plugin-transform-reserved-words": "^7.23.3", + "@babel/plugin-transform-shorthand-properties": "^7.23.3", + "@babel/plugin-transform-spread": "^7.23.3", + "@babel/plugin-transform-sticky-regex": "^7.23.3", + "@babel/plugin-transform-template-literals": "^7.23.3", + "@babel/plugin-transform-typeof-symbol": "^7.23.3", + "@babel/plugin-transform-unicode-escapes": "^7.23.3", + "@babel/plugin-transform-unicode-property-regex": "^7.23.3", + "@babel/plugin-transform-unicode-regex": "^7.23.3", + "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.6", + "babel-plugin-polyfill-corejs3": "^0.8.5", + "babel-plugin-polyfill-regenerator": "^0.5.3", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/fastq": { - "version": "1.15.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==", "dev": true, - "license": "ISC", "dependencies": { - "reusify": "^1.0.4" + "@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/fetch-blob": { - "version": "3.2.0", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "license": "MIT", + "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.23.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", + "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", + "dev": true, "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" + "regenerator-runtime": "^0.14.0" }, "engines": { - "node": "^12.20 || >= 14.13" + "node": ">=6.9.0" } }, - "node_modules/file-entry-cache": { - "version": "6.0.1", + "node_modules/@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, - "license": "MIT", "dependencies": { - "flat-cache": "^3.0.4" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=6.9.0" } }, - "node_modules/fill-range": { - "version": "7.0.1", + "node_modules/@babel/traverse": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.3.tgz", + "integrity": "sha512-+K0yF1/9yR0oHdE0StHuEj3uTPzwwbrLGfNOndVJVV2TqA5+j3oljJUb4nmB954FLGjNem976+B+eDuLIjesiQ==", "dev": true, - "license": "MIT", "dependencies": { - "to-regex-range": "^5.0.1" + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.3", + "@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.23.3", + "@babel/types": "^7.23.3", + "debug": "^4.1.0", + "globals": "^11.1.0" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" } }, - "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" - }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, "engines": { - "node": ">= 0.8" + "node": ">=4" } }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "license": "MIT", + "node_modules/@babel/types": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.3.tgz", + "integrity": "sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw==", + "dev": true, "dependencies": { - "ms": "2.0.0" + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "license": "MIT" + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true }, - "node_modules/find-up": { - "version": "5.0.0", + "node_modules/@eslint/eslintrc": { + "version": "1.4.1", "dev": true, "license": "MIT", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.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": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/eslint" } }, - "node_modules/flat-cache": { - "version": "3.0.4", + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", "dev": true, "license": "MIT", "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/flatted": { - "version": "3.2.7", - "dev": true, - "license": "ISC" - }, - "node_modules/for-each": { - "version": "0.3.3", + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "is-callable": "^1.1.3" + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "license": "MIT", + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.8", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "fetch-blob": "^3.1.2" + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" }, "engines": { - "node": ">=12.20.0" + "node": ">=10.10.0" } }, - "node_modules/forwarded": { - "version": "0.2.0", + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.6" + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/fresh": { - "version": "0.5.2", - "license": "MIT", + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">= 0.6" + "node": "*" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "license": "ISC" + "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/function-bind": { - "version": "1.1.1", - "license": "MIT" + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "dev": true, + "license": "BSD-3-Clause" }, - "node_modules/function.prototype.name": { - "version": "1.1.5", + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" + "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": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/functions-have-names": { - "version": "1.2.3", + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "dependencies": { + "sprintf-js": "~1.0.2" } }, - "node_modules/get-intrinsic": { - "version": "1.1.3", - "license": "MIT", + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=8" } }, - "node_modules/get-stream": { - "version": "6.0.1", + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/get-symbol-description": { - "version": "1.0.0", + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "p-locate": "^4.1.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/glob": { - "version": "8.0.3", - "license": "ISC", + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "p-try": "^2.0.0" }, "engines": { - "node": ">=12" + "node": ">=6" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/glob-parent": { - "version": "6.0.2", + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, - "license": "ISC", "dependencies": { - "is-glob": "^4.0.3" + "p-limit": "^2.2.0" }, "engines": { - "node": ">=10.13.0" + "node": ">=8" } }, - "node_modules/globals": { - "version": "13.19.0", + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globalthis": { - "version": "1.0.3", + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, - "license": "MIT", - "dependencies": { - "define-properties": "^1.1.3" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/gopd": { - "version": "1.0.1", + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", "dev": true, - "license": "MIT", "dependencies": { - "get-intrinsic": "^1.1.3" + "@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" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "license": "ISC" - }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", "dev": true, - "license": "MIT" - }, - "node_modules/handlebars": { - "version": "4.7.7", - "license": "MIT", "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.0", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" + "@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": ">=0.4.7" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, - "optionalDependencies": { - "uglify-js": "^3.1.4" + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/has": { - "version": "1.0.3", - "license": "MIT", + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, "dependencies": { - "function-bind": "^1.1.1" + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" }, "engines": { - "node": ">= 0.4.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/has-bigints": { - "version": "1.0.2", + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/has-flag": { - "version": "4.0.0", + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", "dev": true, - "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.0", + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", "dev": true, - "license": "MIT", "dependencies": { - "get-intrinsic": "^1.1.1" + "@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" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/has-proto": { - "version": "1.0.1", + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/has-symbols": { - "version": "1.0.3", - "license": "MIT", - "engines": { - "node": ">= 0.4" + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "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" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/has-tostringtag": { - "version": "1.0.0", + "node_modules/@jest/reporters/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "license": "MIT", "dependencies": { - "has-symbols": "^1.0.2" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@jest/reporters/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, "engines": { - "node": ">= 0.4" + "node": "*" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/http-errors": { - "version": "2.0.0", - "license": "MIT", + "node_modules/@jest/reporters/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">= 0.8" + "node": "*" } }, - "node_modules/human-signals": { - "version": "3.0.1", + "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==", "dev": true, - "license": "Apache-2.0", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, "engines": { - "node": ">=12.20.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/husky": { - "version": "8.0.3", - "license": "MIT", - "bin": { - "husky": "lib/bin.js" + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" }, "engines": { - "node": ">=14" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" }, - "funding": { - "url": "https://github.com/sponsors/typicode" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "license": "MIT", + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/ignore": { - "version": "5.2.4", + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", "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": ">= 4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/import-fresh": { - "version": "3.3.0", + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, - "license": "MIT", "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "@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": ">=6" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=6.0.0" } }, - "node_modules/imurmurhash": { - "version": "0.1.4", + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", "dev": true, - "license": "MIT", "engines": { - "node": ">=0.8.19" + "node": ">=6.0.0" } }, - "node_modules/indent-string": { - "version": "4.0.0", + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", "dev": true, - "license": "MIT", "engines": { - "node": ">=8" + "node": ">=6.0.0" } }, - "node_modules/inflight": { - "version": "1.0.6", - "license": "ISC", + "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.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, "dependencies": { - "once": "^1.3.0", - "wrappy": "1" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/inherits": { - "version": "2.0.4", - "license": "ISC" - }, - "node_modules/internal-slot": { - "version": "1.0.4", + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", "dev": true, "license": "MIT", "dependencies": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "side-channel": "^1.0.4" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, "engines": { - "node": ">= 0.4" + "node": ">= 8" } }, - "node_modules/ipaddr.js": { - "version": "1.9.1", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, "license": "MIT", "engines": { - "node": ">= 0.10" + "node": ">= 8" } }, - "node_modules/is-array-buffer": { - "version": "3.0.1", + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-typed-array": "^1.1.10" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">= 8" } }, - "node_modules/is-bigint": { - "version": "1.0.4", + "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/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", "dev": true, - "license": "MIT", "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "type-detect": "4.0.8" } }, - "node_modules/is-boolean-object": { - "version": "1.1.2", + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", "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" + "@sinonjs/commons": "^3.0.0" } }, - "node_modules/is-buffer": { - "version": "1.1.6", - "license": "MIT" - }, - "node_modules/is-callable": { - "version": "1.2.7", + "node_modules/@types/babel__core": { + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.4.tgz", + "integrity": "sha512-mLnSC22IC4vcWiuObSRjrLd9XcBTGf59vUSoq2jkQDJ/QQ8PMI9rSuzE+aEV8karUMbskw07bKYoUJCKTUaygg==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" } }, - "node_modules/is-core-module": { - "version": "2.11.0", + "node_modules/@types/babel__generator": { + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.7.tgz", + "integrity": "sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==", "dev": true, - "license": "MIT", "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "@babel/types": "^7.0.0" } }, - "node_modules/is-date-object": { - "version": "1.0.5", + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, - "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" } }, - "node_modules/is-extglob": { - "version": "2.1.1", + "node_modules/@types/babel__traverse": { + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz", + "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" + "dependencies": { + "@babel/types": "^7.20.7" } }, - "node_modules/is-fullwidth-code-point": { - "version": "4.0.0", + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "dependencies": { + "@types/node": "*" } }, - "node_modules/is-glob": { - "version": "4.0.3", + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", "dev": true, - "license": "MIT", "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" + "@types/istanbul-lib-coverage": "*" } }, - "node_modules/is-negative-zero": { - "version": "2.0.2", + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "dependencies": { + "@types/istanbul-lib-report": "*" } }, - "node_modules/is-number": { - "version": "7.0.0", + "node_modules/@types/json5": { + "version": "0.0.29", "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } + "license": "MIT" }, - "node_modules/is-number-object": { - "version": "1.0.7", + "node_modules/@types/node": { + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz", + "integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==", "dev": true, - "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "undici-types": "~5.26.4" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "17.0.31", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.31.tgz", + "integrity": "sha512-bocYSx4DI8TmdlvxqGpVNXOgCNR1Jj0gNPhhAY+iz1rgKDAaYrAYdFYnhDV1IFuiuVc9HkOwyDcFxaTElF3/wg==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "@types/yargs-parser": "*" } }, - "node_modules/is-regex": { - "version": "1.1.4", - "dev": true, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/accepts": { + "version": "1.3.8", "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 0.6" } }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", + "node_modules/acorn": { + "version": "8.8.1", "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2" + "bin": { + "acorn": "bin/acorn" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=0.4.0" } }, - "node_modules/is-stream": { - "version": "3.0.0", + "node_modules/acorn-jsx": { + "version": "5.3.2", "dev": true, "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/is-string": { - "version": "1.0.7", + "node_modules/aggregate-error": { + "version": "3.1.0", "dev": true, "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/is-symbol": { - "version": "1.0.4", + "node_modules/ajv": { + "version": "6.12.6", "dev": true, "license": "MIT", "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/is-typed-array": { - "version": "1.1.10", + "node_modules/ansi-escapes": { + "version": "4.3.2", "dev": true, "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" + "type-fest": "^0.21.3" }, "engines": { - "node": ">= 0.4" + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-weakref": { - "version": "1.0.2", + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2" + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/isexe": { - "version": "2.0.0", + "node_modules/ansi-regex": { + "version": "5.0.1", "dev": true, - "license": "ISC" + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "node_modules/js-sdsl": { - "version": "4.2.0", + "node_modules/ansi-styles": { + "version": "4.3.0", "dev": true, "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/js-yaml": { - "version": "4.1.0", - "dev": true, - "license": "MIT", + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dependencies": { - "argparse": "^2.0.1" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">= 8" } }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "dev": true, - "license": "MIT" + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "dev": true, + "node_modules/argparse": { + "version": "2.0.1", + "license": "Python-2.0" + }, + "node_modules/array-flatten": { + "version": "1.1.1", "license": "MIT" }, - "node_modules/json5": { - "version": "1.0.2", + "node_modules/array-includes": { + "version": "3.1.6", "dev": true, "license": "MIT", "dependencies": { - "minimist": "^1.2.0" + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" }, - "bin": { - "json5": "lib/cli.js" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/levn": { - "version": "0.4.1", + "node_modules/array.prototype.flat": { + "version": "1.3.1", "dev": true, "license": "MIT", "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/lilconfig": { - "version": "2.0.6", + "node_modules/array.prototype.flatmap": { + "version": "1.3.1", "dev": true, "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, "engines": { - "node": ">=10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/linkify-it": { - "version": "4.0.1", + "node_modules/astral-regex": { + "version": "2.0.0", + "dev": true, "license": "MIT", - "dependencies": { - "uc.micro": "^1.0.1" + "engines": { + "node": ">=8" } }, - "node_modules/lint-staged": { - "version": "13.1.0", + "node_modules/available-typed-arrays": { + "version": "1.0.5", "dev": true, "license": "MIT", - "dependencies": { - "cli-truncate": "^3.1.0", - "colorette": "^2.0.19", - "commander": "^9.4.1", - "debug": "^4.3.4", - "execa": "^6.1.0", - "lilconfig": "2.0.6", - "listr2": "^5.0.5", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "object-inspect": "^1.12.2", - "pidtree": "^0.6.0", - "string-argv": "^0.3.1", - "yaml": "^2.1.3" - }, - "bin": { - "lint-staged": "bin/lint-staged.js" - }, "engines": { - "node": "^14.13.1 || >=16.0.0" + "node": ">= 0.4" }, "funding": { - "url": "https://opencollective.com/lint-staged" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/listr2": { - "version": "5.0.7", + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", "dev": true, - "license": "MIT", "dependencies": { - "cli-truncate": "^2.1.0", - "colorette": "^2.0.19", - "log-update": "^4.0.0", - "p-map": "^4.0.0", - "rfdc": "^1.3.0", - "rxjs": "^7.8.0", - "through": "^2.3.8", - "wrap-ansi": "^7.0.0" + "@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.13.1 || >=16.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { - "enquirer": ">= 2.3.0 < 3" - }, - "peerDependenciesMeta": { - "enquirer": { - "optional": true - } + "@babel/core": "^7.8.0" } }, - "node_modules/listr2/node_modules/cli-truncate": { - "version": "2.1.0", + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, - "license": "MIT", "dependencies": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/listr2/node_modules/emoji-regex": { - "version": "8.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/listr2/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", "dev": true, - "license": "MIT", + "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/listr2/node_modules/slice-ansi": { - "version": "3.0.0", + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", "dev": true, - "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/listr2/node_modules/string-width": { - "version": "4.2.3", + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.6.tgz", + "integrity": "sha512-jhHiWVZIlnPbEUKSSNb9YoWcQGdlTLq7z1GHL4AjFxaoOUMuuEVJ+Y4pAaQUGOGk93YsVCKPbqbfw3m0SM6H8Q==", "dev": true, - "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.4.3", + "semver": "^6.3.1" }, - "engines": { - "node": ">=8" + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/locate-path": { - "version": "6.0.0", + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.8.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.6.tgz", + "integrity": "sha512-leDIc4l4tUgU7str5BWLS2h8q2N4Nf6lGZP6UrNDxdtfF2g69eJ5L0H7S8A5Ln/arfFAfHor5InAdZuIOwZdgQ==", "dev": true, - "license": "MIT", "dependencies": { - "p-locate": "^5.0.0" + "@babel/helper-define-polyfill-provider": "^0.4.3", + "core-js-compat": "^3.33.1" }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/lodash.merge": { - "version": "4.6.2", + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.3.tgz", + "integrity": "sha512-8sHeDOmXC8csczMrYEOf0UTNa4yE2SxV5JGeT/LP1n0OYVDUUFPxG9vdk2AlDlIit4t+Kf0xCtpgXPBwnn/9pw==", "dev": true, - "license": "MIT" + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.4.3" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } }, - "node_modules/log-update": { - "version": "4.0.0", + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", "dev": true, - "license": "MIT", "dependencies": { - "ansi-escapes": "^4.3.0", - "cli-cursor": "^3.1.0", - "slice-ansi": "^4.0.0", - "wrap-ansi": "^6.2.0" + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" }, "engines": { - "node": ">=10" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/log-update/node_modules/emoji-regex": { - "version": "8.0.0", - "dev": true, + "node_modules/balanced-match": { + "version": "1.0.2", "license": "MIT" }, - "node_modules/log-update/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "dev": true, + "node_modules/basic-auth": { + "version": "2.0.1", "license": "MIT", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/basic-auth/node_modules/safe-buffer": { + "version": "5.1.2", + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "engines": { "node": ">=8" } }, - "node_modules/log-update/node_modules/slice-ansi": { - "version": "4.0.0", - "dev": true, + "node_modules/body-parser": { + "version": "1.20.1", "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" + "bytes": "3.1.2", + "content-type": "~1.0.4", + "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.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/log-update/node_modules/string-width": { - "version": "4.2.3", - "dev": true, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" + "ms": "2.0.0" } }, - "node_modules/log-update/node_modules/wrap-ansi": { - "version": "6.2.0", - "dev": true, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" + "balanced-match": "^1.0.0" } }, - "node_modules/lru-cache": { - "version": "6.0.0", - "dev": true, - "license": "ISC", + "node_modules/braces": { + "version": "3.0.2", + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "fill-range": "^7.0.1" }, "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/markdown-it": { - "version": "13.0.1", - "license": "MIT", + "node_modules/browserslist": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "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" + } + ], "dependencies": { - "argparse": "^2.0.1", - "entities": "~3.0.1", - "linkify-it": "^4.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.13" }, "bin": { - "markdown-it": "bin/markdown-it.js" + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/md5": { - "version": "2.3.0", - "license": "BSD-3-Clause", + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, "dependencies": { - "charenc": "0.0.2", - "crypt": "0.0.2", - "is-buffer": "~1.1.6" - } - }, - "node_modules/mdurl": { - "version": "1.0.1", - "license": "MIT" - }, - "node_modules/media-typer": { - "version": "0.3.0", - "license": "MIT", - "engines": { - "node": ">= 0.6" + "node-int64": "^0.4.0" } }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "license": "MIT" + "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==" }, - "node_modules/merge-stream": { - "version": "2.0.0", + "node_modules/builtins": { + "version": "5.0.1", "dev": true, - "license": "MIT" - }, - "node_modules/methods": { - "version": "1.1.2", "license": "MIT", - "engines": { - "node": ">= 0.6" + "dependencies": { + "semver": "^7.0.0" } }, - "node_modules/micromatch": { - "version": "4.0.5", + "node_modules/builtins/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, - "license": "MIT", "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" + "lru-cache": "^6.0.0" }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "license": "MIT", "bin": { - "mime": "cli.js" + "semver": "bin/semver.js" }, "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "license": "MIT", - "engines": { - "node": ">= 0.6" + "node": ">=10" } }, - "node_modules/mime-types": { - "version": "2.1.35", - "license": "MIT", + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", "dependencies": { - "mime-db": "1.52.0" + "streamsearch": "^1.1.0" }, "engines": { - "node": ">= 0.6" + "node": ">=10.16.0" } }, - "node_modules/mimic-fn": { - "version": "4.0.0", - "dev": true, + "node_modules/bytes": { + "version": "3.1.2", "license": "MIT", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.8" } }, - "node_modules/minimatch": { - "version": "5.1.0", - "license": "ISC", + "node_modules/call-bind": { + "version": "1.0.2", + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.1" + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" }, - "engines": { - "node": ">=10" - } - }, - "node_modules/minimist": { - "version": "1.2.7", - "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/moment": { - "version": "2.29.4", + "node_modules/callsites": { + "version": "3.1.0", + "dev": true, "license": "MIT", "engines": { - "node": "*" + "node": ">=6" } }, - "node_modules/ms": { - "version": "2.1.2", - "license": "MIT" - }, - "node_modules/natural-compare": { - "version": "1.4.0", + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "0.6.3", - "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=6" } }, - "node_modules/neo-async": { - "version": "2.6.2", - "license": "MIT" - }, - "node_modules/node-domexception": { - "version": "1.0.0", + "node_modules/caniuse-lite": { + "version": "1.0.30001561", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001561.tgz", + "integrity": "sha512-NTt0DNoKe958Q0BE0j0c1V9jbUzhBxHIEJy7asmGrpE0yG63KTV7PLHPnK2E1O9RsQrQ081I3NLuXGS6zht3cw==", + "dev": true, "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" }, { "type": "github", - "url": "https://paypal.me/jimmywarting" + "url": "https://github.com/sponsors/ai" } - ], - "license": "MIT", - "engines": { - "node": ">=10.5.0" - } + ] }, - "node_modules/node-fetch": { - "version": "3.3.0", + "node_modules/chalk": { + "version": "4.1.2", + "dev": true, "license": "MIT", "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/normalize-path": { - "version": "3.0.0", + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true, - "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/npm-run-path": { - "version": "5.1.0", - "dev": true, - "license": "MIT", + "node_modules/charenc": { + "version": "0.0.2", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], "dependencies": { - "path-key": "^4.0.0" + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">= 8.10.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "optionalDependencies": { + "fsevents": "~2.3.3" } }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">= 6" } }, - "node_modules/object-assign": { - "version": "4.1.1", - "license": "MIT", + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/object-inspect": { - "version": "1.12.2", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "node_modules/cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "dev": true }, - "node_modules/object-keys": { - "version": "1.1.1", + "node_modules/clean-stack": { + "version": "2.2.0", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=6" } }, - "node_modules/object.assign": { - "version": "4.1.4", + "node_modules/cli-cursor": { + "version": "3.1.0", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" + "restore-cursor": "^3.1.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/object.values": { - "version": "1.1.6", + "node_modules/cli-truncate": { + "version": "3.1.0", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "slice-ansi": "^5.0.0", + "string-width": "^5.0.0" }, "engines": { - "node": ">= 0.4" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/on-finished": { - "version": "2.4.1", - "license": "MIT", + "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": { - "ee-first": "1.1.1" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">=12" } }, - "node_modules/once": { - "version": "1.4.0", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } + "node_modules/cliui/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_modules/onetime": { - "version": "6.0.0", + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^4.0.0" - }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/optionator": { - "version": "0.9.1", + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "license": "MIT", "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">= 0.8.0" + "node": ">=8" } }, - "node_modules/p-limit": { - "version": "3.1.0", + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" } }, - "node_modules/p-locate": { - "version": "5.0.0", + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true + }, + "node_modules/color-convert": { + "version": "2.0.1", "dev": true, "license": "MIT", "dependencies": { - "p-limit": "^3.0.2" + "color-name": "~1.1.4" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=7.0.0" } }, - "node_modules/p-map": { - "version": "4.0.0", + "node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.19", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "dev": true, - "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=14" } }, - "node_modules/parent-module": { - "version": "1.0.1", - "dev": true, + "node_modules/concat-map": { + "version": "0.0.1", + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", "license": "MIT", "dependencies": { - "callsites": "^3.0.0" + "safe-buffer": "5.2.1" }, "engines": { - "node": ">=6" + "node": ">= 0.6" } }, - "node_modules/parseurl": { - "version": "1.3.3", + "node_modules/content-type": { + "version": "1.0.4", "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">= 0.6" } }, - "node_modules/path-exists": { - "version": "4.0.0", - "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/cookie": { + "version": "0.5.0", "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 0.6" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "dev": true, + "node_modules/cookie-parser": { + "version": "1.4.6", "license": "MIT", + "dependencies": { + "cookie": "0.4.1", + "cookie-signature": "1.0.6" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8.0" } }, - "node_modules/path-key": { - "version": "3.1.1", - "dev": true, + "node_modules/cookie-parser/node_modules/cookie": { + "version": "0.4.1", "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 0.6" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "dev": true, - "license": "MIT" - }, - "node_modules/path-to-regexp": { - "version": "0.1.7", + "node_modules/cookie-signature": { + "version": "1.0.6", "license": "MIT" }, - "node_modules/picomatch": { - "version": "2.3.1", - "dev": true, + "node_modules/copy-env-cli": { + "version": "1.0.0", "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "bin": { + "copy-env-cli": "bin.js" } }, - "node_modules/pidtree": { - "version": "0.6.0", + "node_modules/core-js-compat": { + "version": "3.33.2", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.33.2.tgz", + "integrity": "sha512-axfo+wxFVxnqf8RvxTzoAlzW4gRoacrHeoFlc9n0x50+7BEyZL/Rt3hicaED1/CEd7I6tPCPVUYcJwCMO5XUYw==", "dev": true, - "license": "MIT", - "bin": { - "pidtree": "bin/pidtree.js" + "dependencies": { + "browserslist": "^4.22.1" }, - "engines": { - "node": ">=0.10" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" } }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "dev": true, + "node_modules/cors": { + "version": "2.8.5", "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, "engines": { - "node": ">= 0.8.0" + "node": ">= 0.10" } }, - "node_modules/prettier": { - "version": "2.8.3", + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", "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": { - "prettier": "bin-prettier.js" + "create-jest": "bin/create-jest.js" }, "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/proxy-addr": { - "version": "2.0.7", + "node_modules/cross-spawn": { + "version": "7.0.3", + "dev": true, "license": "MIT", "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { - "node": ">= 0.10" + "node": ">= 8" } }, - "node_modules/punycode": { - "version": "2.2.0", - "dev": true, + "node_modules/crypt": { + "version": "0.0.2", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.0", "license": "MIT", "engines": { - "node": ">=6" + "node": ">= 12" } }, - "node_modules/qs": { - "version": "6.11.0", - "license": "BSD-3-Clause", + "node_modules/debug": { + "version": "4.3.4", + "license": "MIT", "dependencies": { - "side-channel": "^1.0.4" + "ms": "2.1.2" }, "engines": { - "node": ">=0.6" + "node": ">=6.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/queue-microtask": { - "version": "1.2.3", + "node_modules/dedent": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", + "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", "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" + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true } - ], - "license": "MIT" - }, - "node_modules/queue-promise": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/queue-promise/-/queue-promise-2.2.1.tgz", - "integrity": "sha512-C3eyRwLF9m6dPV4MtqMVFX+Xmc7keZ9Ievm3jJ/wWM5t3uVbFnGsJXwpYzZ4LaIEcX9bss/mdaKzyrO6xheRuA==", - "engines": { - "node": ">=8.12.0" } }, - "node_modules/range-parser": { - "version": "1.2.1", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } + "node_modules/deep-is": { + "version": "0.1.4", + "dev": true, + "license": "MIT" }, - "node_modules/raw-body": { - "version": "2.5.1", - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, "engines": { - "node": ">= 0.8" + "node": ">=0.10.0" } }, - "node_modules/regexp.prototype.flags": { - "version": "1.4.3", + "node_modules/define-properties": { + "version": "1.1.4", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" }, "engines": { "node": ">= 0.4" @@ -2959,200 +3664,291 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/regexpp": { - "version": "3.2.0", - "dev": true, + "node_modules/depd": { + "version": "2.0.0", "license": "MIT", "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/resolve": { - "version": "1.22.1", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 0.8" } }, - "node_modules/resolve-from": { - "version": "4.0.0", - "dev": true, + "node_modules/destroy": { + "version": "1.2.0", "license": "MIT", "engines": { - "node": ">=4" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/restore-cursor": { + "node_modules/detect-newline": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true, - "license": "MIT", - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, "engines": { "node": ">=8" } }, - "node_modules/restore-cursor/node_modules/mimic-fn": { - "version": "2.1.0", + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", "dev": true, - "license": "MIT", "engines": { - "node": ">=6" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/restore-cursor/node_modules/onetime": { - "version": "5.1.2", + "node_modules/doctrine": { + "version": "3.0.0", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "mimic-fn": "^2.1.0" + "esutils": "^2.0.2" }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6.0.0" } }, - "node_modules/reusify": { - "version": "1.0.4", - "dev": true, - "license": "MIT", + "node_modules/dotenv": { + "version": "16.0.3", + "license": "BSD-2-Clause", "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" + "node": ">=12" } }, - "node_modules/rfdc": { - "version": "1.3.0", + "node_modules/eastasianwidth": { + "version": "0.2.0", "dev": true, "license": "MIT" }, - "node_modules/rimraf": { - "version": "3.0.2", + "node_modules/ee-first": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.581", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.581.tgz", + "integrity": "sha512-6uhqWBIapTJUxgPTCHH9sqdbxIMPt7oXl0VcAL1kOtlU6aECdcMncCrX5Z7sHQ/invtrC9jUQUef7+HhO8vVFw==", + "dev": true + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" + "engines": { + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sindresorhus/emittery?sponsor=1" } }, - "node_modules/rimraf/node_modules/brace-expansion": { - "version": "1.1.11", + "node_modules/emoji-regex": { + "version": "9.2.2", "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "1.0.2", "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "engines": { + "node": ">= 0.8" } }, - "node_modules/rimraf/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" - }, + "node_modules/entities": { + "version": "3.0.1", + "license": "BSD-2-Clause", "engines": { - "node": "*" + "node": ">=0.12" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "3.1.2", + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, - "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.21.1", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.4", + "is-array-buffer": "^3.0.1", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" }, "engines": { - "node": "*" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/rss-generator": { - "version": "0.0.3", + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "dev": true, "license": "MIT", "dependencies": { - "mime-types": "2.1.13", - "moment": "^2.19.1", - "xml": "1.0.1" + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/rss-generator/node_modules/mime-db": { - "version": "1.25.0", + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.6" + "dependencies": { + "has": "^1.0.3" } }, - "node_modules/rss-generator/node_modules/mime-types": { - "version": "2.1.13", + "node_modules/es-to-primitive": { + "version": "1.2.1", + "dev": true, "license": "MIT", "dependencies": { - "mime-db": "~1.25.0" + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/run-parallel": { - "version": "1.2.0", + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.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": { - "queue-microtask": "^1.2.2" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/rxjs": { - "version": "7.8.0", + "node_modules/eslint": { + "version": "8.32.0", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "tslib": "^2.1.0" + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "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.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "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", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "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.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "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/safe-buffer": { - "version": "5.2.1", + "node_modules/eslint-config-prettier": { + "version": "8.6.0", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-config-standard": { + "version": "17.0.0", + "dev": true, "funding": [ { "type": "github", @@ -3167,1889 +3963,8954 @@ "url": "https://feross.org/support" } ], - "license": "MIT" + "license": "MIT", + "peerDependencies": { + "eslint": "^8.0.1", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-n": "^15.0.0", + "eslint-plugin-promise": "^6.0.0" + } }, - "node_modules/safe-regex-test": { - "version": "1.0.0", + "node_modules/eslint-import-resolver-node": { + "version": "0.3.7", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "debug": "^3.2.7", + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" } }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "license": "MIT" - }, - "node_modules/semver": { - "version": "6.3.0", + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" } }, - "node_modules/send": { - "version": "0.18.0", + "node_modules/eslint-module-utils": { + "version": "2.7.4", + "dev": true, "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" + "debug": "^3.2.7" }, "engines": { - "node": ">= 0.8.0" + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "dev": true, "license": "MIT", "dependencies": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "license": "MIT" - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "license": "MIT" - }, - "node_modules/serve-static": { - "version": "1.15.0", + "node_modules/eslint-plugin-es": { + "version": "4.1.0", + "dev": true, "license": "MIT", "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">=8.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=4.19.1" } }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "license": "ISC" - }, - "node_modules/shebang-command": { - "version": "2.0.0", + "node_modules/eslint-plugin-es/node_modules/eslint-utils": { + "version": "2.1.0", "dev": true, "license": "MIT", "dependencies": { - "shebang-regex": "^3.0.0" + "eslint-visitor-keys": "^1.1.0" }, "engines": { - "node": ">=8" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" } }, - "node_modules/shebang-regex": { - "version": "3.0.0", + "node_modules/eslint-plugin-es/node_modules/eslint-visitor-keys": { + "version": "1.3.0", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/side-channel": { - "version": "1.0.4", + "node_modules/eslint-plugin-import": { + "version": "2.27.5", + "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", + "has": "^1.0.3", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", + "tsconfig-paths": "^3.14.1" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" } }, - "node_modules/signal-exit": { - "version": "3.0.7", - "dev": true, - "license": "ISC" - }, - "node_modules/slice-ansi": { - "version": "5.0.0", + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.11", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^6.0.0", - "is-fullwidth-code-point": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "6.2.1", + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", "dev": true, "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "dependencies": { + "ms": "^2.1.1" } }, - "node_modules/source-map": { - "version": "0.6.1", - "license": "BSD-3-Clause", + "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/statuses": { - "version": "2.0.1", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/string-argv": { - "version": "0.3.1", + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", "dev": true, - "license": "MIT", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=0.6.19" + "node": "*" } }, - "node_modules/string-width": { - "version": "5.1.2", + "node_modules/eslint-plugin-n": { + "version": "15.6.1", "dev": true, "license": "MIT", "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" + "builtins": "^5.0.1", + "eslint-plugin-es": "^4.1.0", + "eslint-utils": "^3.0.0", + "ignore": "^5.1.1", + "is-core-module": "^2.11.0", + "minimatch": "^3.1.2", + "resolve": "^1.22.1", + "semver": "^7.3.8" }, "engines": { - "node": ">=12" + "node": ">=12.22.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=7.0.0" } }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "6.0.1", + "node_modules/eslint-plugin-n/node_modules/brace-expansion": { + "version": "1.1.11", "dev": true, "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "7.0.1", + "node_modules/eslint-plugin-n/node_modules/minimatch": { + "version": "3.1.2", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "ansi-regex": "^6.0.1" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": "*" } }, - "node_modules/string.prototype.trimend": { - "version": "1.0.6", + "node_modules/eslint-plugin-n/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "lru-cache": "^6.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.6", + "node_modules/eslint-plugin-promise": { + "version": "6.1.1", "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "license": "ISC", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" } }, - "node_modules/strip-ansi": { - "version": "6.0.1", + "node_modules/eslint-scope": { + "version": "7.1.1", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "ansi-regex": "^5.0.1" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">=8" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/strip-bom": { + "node_modules/eslint-utils": { "version": "3.0.0", "dev": true, "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, "engines": { - "node": ">=4" - } - }, - "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/strip-json-comments": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" + "url": "https://github.com/sponsors/mysticatea" }, - "engines": { - "node": ">=8" + "peerDependencies": { + "eslint": ">=5" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=10" } }, - "node_modules/text-table": { - "version": "0.2.0", - "dev": true, - "license": "MIT" - }, - "node_modules/through": { - "version": "2.3.8", - "dev": true, - "license": "MIT" - }, - "node_modules/to-regex-range": { - "version": "5.0.1", + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">=0.6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/tsconfig-paths": { - "version": "3.14.1", + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", "dev": true, "license": "MIT", "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/tslib": { - "version": "2.4.1", - "dev": true, - "license": "0BSD" - }, - "node_modules/type-check": { - "version": "0.4.0", + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "prelude-ls": "^1.2.1" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">= 0.8.0" + "node": "*" } }, - "node_modules/type-fest": { - "version": "0.20.2", + "node_modules/espree": { + "version": "9.4.1", "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", + "license": "BSD-2-Clause", "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://opencollective.com/eslint" } }, - "node_modules/uc.micro": { - "version": "1.0.6", - "license": "MIT" - }, - "node_modules/uglify-js": { - "version": "3.17.4", - "license": "BSD-2-Clause", - "optional": true, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, "bin": { - "uglifyjs": "bin/uglifyjs" + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" }, "engines": { - "node": ">=0.8.0" + "node": ">=4" } }, - "node_modules/unbox-primitive": { - "version": "1.0.2", + "node_modules/esquery": { + "version": "1.4.0", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" + "estraverse": "^5.1.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">=0.10" } }, - "node_modules/uri-js": { - "version": "4.4.1", + "node_modules/esrecurse": { + "version": "4.3.0", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "punycode": "^2.1.0" + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" } }, - "node_modules/utils-merge": { - "version": "1.0.1", - "license": "MIT", + "node_modules/estraverse": { + "version": "5.3.0", + "dev": true, + "license": "BSD-2-Clause", "engines": { - "node": ">= 0.4.0" + "node": ">=4.0" } }, - "node_modules/vary": { - "version": "1.1.2", - "license": "MIT", + "node_modules/esutils": { + "version": "2.0.3", + "dev": true, + "license": "BSD-2-Clause", "engines": { - "node": ">= 0.8" + "node": ">=0.10.0" } }, - "node_modules/web-streams-polyfill": { - "version": "3.2.1", + "node_modules/etag": { + "version": "1.8.1", "license": "MIT", "engines": { - "node": ">= 8" + "node": ">= 0.6" } }, - "node_modules/which": { - "version": "2.0.2", + "node_modules/execa": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", + "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", "dev": true, - "license": "ISC", "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" }, "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" + "node": "^14.18.0 || ^16.14.0 || >=18.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/which-typed-array": { - "version": "1.1.9", + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 0.8.0" } }, - "node_modules/word-wrap": { - "version": "1.2.3", + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", "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": ">=0.10.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/wordwrap": { - "version": "1.0.0", - "license": "MIT" - }, - "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" + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.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": ">=10" + "node": ">= 0.10.0" + } + }, + "node_modules/express-basic-auth": { + "version": "1.2.1", + "license": "MIT", + "dependencies": { + "basic-auth": "^2.0.1" + } + }, + "node_modules/express-handlebars": { + "version": "6.0.6", + "license": "BSD-3-Clause", + "dependencies": { + "glob": "^8.0.2", + "graceful-fs": "^4.2.10", + "handlebars": "^4.7.7" }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "engines": { + "node": ">=v12.22.9" } }, - "node_modules/wrap-ansi/node_modules/emoji-regex": { - "version": "8.0.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/fast-deep-equal": { + "version": "3.1.3", "dev": true, "license": "MIT" }, - "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", + "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/fastq": { + "version": "1.15.0", "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, "engines": { - "node": ">=8" + "node": "^12.20 || >= 14.13" } }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "4.2.3", + "node_modules/file-entry-cache": { + "version": "6.0.1", "dev": true, "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "flat-cache": "^3.0.4" }, "engines": { - "node": ">=8" + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "license": "ISC" - }, - "node_modules/xml": { - "version": "1.0.1", - "license": "MIT" - }, - "node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" + "node_modules/fill-range": { + "version": "7.0.1", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } }, - "node_modules/yaml": { - "version": "2.2.1", - "dev": true, - "license": "ISC", + "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": ">= 14" + "node": ">= 0.8" } }, - "node_modules/yocto-queue": { - "version": "0.1.0", + "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" } - } - }, - "dependencies": { - "@eslint/eslintrc": { - "version": "1.4.1", + }, + "node_modules/flat-cache": { + "version": "3.0.4", "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.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" - }, + "license": "MIT", "dependencies": { - "brace-expansion": { - "version": "1.1.11", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "minimatch": { - "version": "3.1.2", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - } + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" } }, - "@humanwhocodes/config-array": { - "version": "0.11.8", + "node_modules/flatted": { + "version": "3.2.7", "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - }, + "license": "ISC" + }, + "node_modules/for-each": { + "version": "0.3.3", + "dev": true, + "license": "MIT", "dependencies": { - "brace-expansion": { - "version": "1.1.11", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "minimatch": { - "version": "3.1.2", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - } + "is-callable": "^1.1.3" } }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "dev": true - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "dev": true - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" } }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "node_modules/forwarded": { + "version": "0.2.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "@types/json5": { - "version": "0.0.29", - "dev": true - }, - "accepts": { - "version": "1.3.8", - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" + "node_modules/fresh": { + "version": "0.5.2", + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "acorn": { - "version": "8.8.1", - "dev": true + "node_modules/fs.realpath": { + "version": "1.0.0", + "license": "ISC" }, - "acorn-jsx": { - "version": "5.3.2", - "dev": true, - "requires": {} + "node_modules/function-bind": { + "version": "1.1.1", + "license": "MIT" }, - "aggregate-error": { - "version": "3.1.0", + "node_modules/function.prototype.name": { + "version": "1.1.5", "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "ajv": { - "version": "6.12.6", + "node_modules/functions-have-names": { + "version": "1.2.3", "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "ansi-escapes": { - "version": "4.3.2", + "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, - "requires": { - "type-fest": "^0.21.3" - }, - "dependencies": { - "type-fest": { - "version": "0.21.3", - "dev": true - } + "engines": { + "node": ">=6.9.0" } }, - "ansi-regex": { - "version": "5.0.1", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, - "requires": { - "color-convert": "^2.0.1" + "engines": { + "node": "6.* || 8.* || >= 10.*" } }, - "argparse": { - "version": "2.0.1" - }, - "array-flatten": { - "version": "1.1.1" + "node_modules/get-intrinsic": { + "version": "1.1.3", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "array-includes": { - "version": "3.1.6", + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "is-string": "^1.0.7" + "engines": { + "node": ">=8.0.0" } }, - "array.prototype.flat": { - "version": "1.3.1", + "node_modules/get-stream": { + "version": "6.0.1", "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "array.prototype.flatmap": { - "version": "1.3.1", + "node_modules/get-symbol-description": { + "version": "1.0.0", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" - } - }, - "astral-regex": { - "version": "2.0.0", - "dev": true - }, - "available-typed-arrays": { - "version": "1.0.5", - "dev": true - }, - "balanced-match": { - "version": "1.0.2" - }, - "basic-auth": { - "version": "2.0.1", - "requires": { - "safe-buffer": "5.1.2" + "get-intrinsic": "^1.1.1" }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2" - } - } - }, - "body-parser": { - "version": "1.20.1", - "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "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.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" + "engines": { + "node": ">= 0.4" }, - "dependencies": { - "debug": { - "version": "2.6.9", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0" - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "brace-expansion": { - "version": "2.0.1", - "requires": { - "balanced-match": "^1.0.0" + "node_modules/glob": { + "version": "8.0.3", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "braces": { - "version": "3.0.2", + "node_modules/glob-parent": { + "version": "6.0.2", "dev": true, - "requires": { - "fill-range": "^7.0.1" + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" } }, - "builtins": { - "version": "5.0.1", + "node_modules/globals": { + "version": "13.19.0", "dev": true, - "requires": { - "semver": "^7.0.0" - }, + "license": "MIT", "dependencies": { - "semver": { - "version": "7.3.8", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "bytes": { - "version": "3.1.2" + "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" + } }, - "call-bind": { - "version": "1.0.2", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "node_modules/gopd": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "callsites": { - "version": "3.1.0", - "dev": true + "node_modules/graceful-fs": { + "version": "4.2.10", + "license": "ISC" }, - "chalk": { - "version": "4.1.2", + "node_modules/grapheme-splitter": { + "version": "1.0.4", "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } + "license": "MIT" }, - "charenc": { - "version": "0.0.2" + "node_modules/handlebars": { + "version": "4.7.7", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } }, - "clean-stack": { - "version": "2.2.0", - "dev": true + "node_modules/has": { + "version": "1.0.3", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } }, - "cli-cursor": { - "version": "3.1.0", + "node_modules/has-bigints": { + "version": "1.0.2", "dev": true, - "requires": { - "restore-cursor": "^3.1.0" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "cli-truncate": { - "version": "3.1.0", + "node_modules/has-flag": { + "version": "4.0.0", "dev": true, - "requires": { - "slice-ansi": "^5.0.0", - "string-width": "^5.0.0" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "color-convert": { - "version": "2.0.1", + "node_modules/has-property-descriptors": { + "version": "1.0.0", "dev": true, - "requires": { - "color-name": "~1.1.4" + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "color-name": { - "version": "1.1.4", - "dev": true - }, - "colorette": { - "version": "2.0.19", - "dev": true - }, - "commander": { - "version": "9.5.0", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "dev": true - }, - "content-disposition": { - "version": "0.5.4", - "requires": { - "safe-buffer": "5.2.1" + "node_modules/has-proto": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "content-type": { - "version": "1.0.4" - }, - "cookie": { - "version": "0.5.0" - }, - "cookie-parser": { - "version": "1.4.6", - "requires": { - "cookie": "0.4.1", - "cookie-signature": "1.0.6" + "node_modules/has-symbols": { + "version": "1.0.3", + "license": "MIT", + "engines": { + "node": ">= 0.4" }, - "dependencies": { - "cookie": { - "version": "0.4.1" - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "cookie-signature": { - "version": "1.0.6" + "node_modules/has-tostringtag": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "copy-env-cli": { - "version": "1.0.0" + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true }, - "cors": { - "version": "2.8.5", - "requires": { - "object-assign": "^4", - "vary": "^1" + "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" } }, - "cross-spawn": { - "version": "7.0.3", + "node_modules/human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "engines": { + "node": ">=14.18.0" } }, - "crypt": { - "version": "0.0.2" + "node_modules/husky": { + "version": "8.0.3", + "license": "MIT", + "bin": { + "husky": "lib/bin.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } }, - "data-uri-to-buffer": { - "version": "4.0.0" + "node_modules/iconv-lite": { + "version": "0.4.24", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } }, - "debug": { - "version": "4.3.4", - "requires": { - "ms": "2.1.2" + "node_modules/ignore": { + "version": "5.2.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" } }, - "deep-is": { - "version": "0.1.4", - "dev": true + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==" }, - "define-properties": { + "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-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_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", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "license": "ISC" + }, + "node_modules/internal-slot": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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-buffer": { + "version": "1.1.6", + "license": "MIT" + }, + "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.11.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has": "^1.0.3" + }, + "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-extglob": { + "version": "2.1.1", + "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", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "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-path-inside": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "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-typed-array": { + "version": "1.1.10", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/isexe": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz", + "integrity": "sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "dependencies": { + "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", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", + "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "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", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "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-changed-files/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/jest-changed-files/node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/jest-changed-files/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-changed-files/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==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/jest-changed-files/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-changed-files/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-changed-files/node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "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-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "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", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "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-config/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/jest-config/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-config/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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==", + "dev": true, + "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", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "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", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "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", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "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", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "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.3" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "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", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "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", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "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", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "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", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "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", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "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-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "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-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "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-runtime/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/jest-runtime/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-runtime/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jest-runtime/node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "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-snapshot/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "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-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "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", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "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", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "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", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-sdsl": { + "version": "4.2.0", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "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/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", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/linkify-it": { + "version": "4.0.1", + "license": "MIT", + "dependencies": { + "uc.micro": "^1.0.1" + } + }, + "node_modules/lint-staged": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.2.3.tgz", + "integrity": "sha512-zVVEXLuQIhr1Y7R7YAWx4TZLdvuzk7DnmrsTNL0fax6Z3jrpFcas+vKbzxhhvp6TA55m1SQuWkpzI1qbfDZbAg==", + "dev": true, + "dependencies": { + "chalk": "5.2.0", + "cli-truncate": "^3.1.0", + "commander": "^10.0.0", + "debug": "^4.3.4", + "execa": "^7.0.0", + "lilconfig": "2.1.0", + "listr2": "^5.0.7", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-inspect": "^1.12.3", + "pidtree": "^0.6.0", + "string-argv": "^0.3.1", + "yaml": "^2.2.2" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": "^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/lint-staged/node_modules/chalk": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", + "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/listr2": { + "version": "5.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^2.1.0", + "colorette": "^2.0.19", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rfdc": "^1.3.0", + "rxjs": "^7.8.0", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": "^14.13.1 || >=16.0.0" + }, + "peerDependencies": { + "enquirer": ">= 2.3.0 < 3" + }, + "peerDependenciesMeta": { + "enquirer": { + "optional": true + } + } + }, + "node_modules/listr2/node_modules/cli-truncate": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/listr2/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/listr2/node_modules/slice-ansi": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/listr2/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/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.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/log-update": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/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/log-update/node_modules/wrap-ansi": { + "version": "6.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/markdown-it": { + "version": "13.0.1", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "~3.0.1", + "linkify-it": "^4.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/md5": { + "version": "2.3.0", + "license": "BSD-3-Clause", + "dependencies": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, + "node_modules/mdurl": { + "version": "1.0.1", + "license": "MIT" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "license": "MIT" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "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/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": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "5.1.0", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/minimist": { + "version": "1.2.7", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/moment": { + "version": "2.29.4", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "license": "MIT" + }, + "node_modules/multer": { + "version": "1.4.5-lts.1", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz", + "integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==", + "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/natural-compare": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "license": "MIT" + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.0", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", + "dev": true + }, + "node_modules/nodemon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.2.tgz", + "integrity": "sha512-9qIN2LNTrEzpOPBaWHTm4Asy1LxXLSickZStAQ4IZe7zsoIpD/A7LWxhZV3t4Zu352uBcqVnRsDXSMR2Sc3lTA==", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/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==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/nodemon/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/nodemon/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/nodemon/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "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/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.6", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "dev": true, + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "license": "MIT" + }, + "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/picomatch": { + "version": "2.3.1", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.6.0", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.3", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "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==", + "dev": true, + "dependencies": { + "@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/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" + }, + "node_modules/punycode": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", + "integrity": "sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, + "node_modules/qs": { + "version": "6.11.0", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "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/queue-promise": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/queue-promise/-/queue-promise-2.2.1.tgz", + "integrity": "sha512-C3eyRwLF9m6dPV4MtqMVFX+Xmc7keZ9Ievm3jJ/wWM5t3uVbFnGsJXwpYzZ4LaIEcX9bss/mdaKzyrO6xheRuA==", + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/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/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==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", + "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==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dev": true, + "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" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "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==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "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/restore-cursor/node_modules/mimic-fn": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "5.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/rimraf": { + "version": "3.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/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/rimraf/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/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/rss-generator": { + "version": "0.0.3", + "license": "MIT", + "dependencies": { + "mime-types": "2.1.13", + "moment": "^2.19.1", + "xml": "1.0.1" + } + }, + "node_modules/rss-generator/node_modules/mime-db": { + "version": "1.25.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/rss-generator/node_modules/mime-types": { + "version": "2.1.13", + "license": "MIT", + "dependencies": { + "mime-db": "~1.25.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "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": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "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/safe-regex-test": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "license": "MIT" + }, + "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/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/send/node_modules/debug": { + "version": "2.6.9", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "license": "MIT" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "license": "MIT", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "dev": true, + "license": "ISC" + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-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/source-map": { + "version": "0.6.1", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/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/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string-argv": { + "version": "0.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width/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/string-width/node_modules/strip-ansi": { + "version": "7.0.1", + "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/string.prototype.trimend": { + "version": "1.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/through": { + "version": "2.3.8", + "dev": true, + "license": "MIT" + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.14.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.4.1", + "dev": true, + "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", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "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-length": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + }, + "node_modules/uc.micro": { + "version": "1.0.6", + "license": "MIT" + }, + "node_modules/uglify-js": { + "version": "3.17.4", + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true, + "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, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "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, + "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, + "engines": { + "node": ">=4" + } + }, + "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": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "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/utils-merge": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.3.tgz", + "integrity": "sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg==", + "dev": true, + "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/vary": { + "version": "1.1.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.2.1", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "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.9", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "license": "MIT" + }, + "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/wrap-ansi/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/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/wrappy": { + "version": "1.0.2", + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/xml": { + "version": "1.0.1", + "license": "MIT" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "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, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "dev": true, + "engines": { + "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, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "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, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/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_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "dev": true, + "requires": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^1.9.0" + } + }, + "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, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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, + "requires": { + "color-name": "1.1.3" + } + }, + "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 + }, + "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==", + "dev": true + }, + "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 + }, + "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, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/compat-data": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.3.tgz", + "integrity": "sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==", + "dev": true + }, + "@babel/core": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.3.tgz", + "integrity": "sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.3", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.2", + "@babel/parser": "^7.23.3", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.3", + "@babel/types": "^7.23.3", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "dependencies": { + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.3.tgz", + "integrity": "sha512-keeZWAV4LU3tW0qRi19HRpabC/ilM0HRBBzf9/k8FFiG4KVpiv0FIy4hHfLfFQZNhziCTPTmd59zoyv6DNISzg==", + "dev": true, + "requires": { + "@babel/types": "^7.23.3", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + } + }, + "@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, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@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, + "requires": { + "@babel/types": "^7.22.15" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.15.tgz", + "integrity": "sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + } + }, + "@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, + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + } + }, + "@babel/helper-define-polyfill-provider": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.3.tgz", + "integrity": "sha512-WBrLmuPP47n7PNwsZ57pqam6G/RGo1vw/87b0Blc53tZNGZ4x7YvZ6HgQe2vo1W/FR20OgjeZuGXzudPiXHFug==", + "dev": true, + "requires": { + "@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" + } + }, + "@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 + }, + "@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, + "requires": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + } + }, + "@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, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@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, + "requires": { + "@babel/types": "^7.23.0" + } + }, + "@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dev": true, + "requires": { + "@babel/types": "^7.22.15" + } + }, + "@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, + "requires": { + "@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" + } + }, + "@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, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true + }, + "@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, + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" + } + }, + "@babel/helper-replace-supers": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", + "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5" + } + }, + "@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, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@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, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@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, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "dev": true + }, + "@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 + }, + "@babel/helper-validator-option": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", + "dev": true + }, + "@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, + "requires": { + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" + } + }, + "@babel/helpers": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz", + "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==", + "dev": true, + "requires": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.2", + "@babel/types": "^7.23.0" + } + }, + "@babel/highlight": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^1.9.0" + } + }, + "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, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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, + "requires": { + "color-name": "1.1.3" + } + }, + "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 + }, + "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==", + "dev": true + }, + "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 + }, + "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, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.3.tgz", + "integrity": "sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==", + "dev": true + }, + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.23.3", + "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.23.3.tgz", + "integrity": "sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.23.3.tgz", + "integrity": "sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.23.3" + } + }, + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.3.tgz", + "integrity": "sha512-XaJak1qcityzrX0/IU5nKHb34VaibwP3saKqG6a/tppelgllOH13LUann4ZCIBcVOeE6H18K4Vx9QKkVww3z/w==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "requires": {} + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-import-assertions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.23.3.tgz", + "integrity": "sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-syntax-import-attributes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.23.3.tgz", + "integrity": "sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", + "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz", + "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz", + "integrity": "sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-async-generator-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.3.tgz", + "integrity": "sha512-59GsVNavGxAXCDDbakWSMJhajASb4kBCqDjqJsv+p5nKdbz7istmZ3HrX3L2LuiI80+zsOADCvooqQH3qGCucQ==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20", + "@babel/plugin-syntax-async-generators": "^7.8.4" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz", + "integrity": "sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz", + "integrity": "sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.3.tgz", + "integrity": "sha512-QPZxHrThbQia7UdvfpaRRlq/J9ciz1J4go0k+lPBXbgaNeY7IQrBj/9ceWjvMMI07/ZBzHl/F0R/2K0qH7jCVw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-class-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.23.3.tgz", + "integrity": "sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-class-static-block": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.23.3.tgz", + "integrity": "sha512-PENDVxdr7ZxKPyi5Ffc0LjXdnJyrJxyqF5T5YjlVg4a0VFfQHW0r8iAtRiDXkfHlu1wwcvdtnndGYIeJLSuRMQ==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.3.tgz", + "integrity": "sha512-FGEQmugvAEu2QtgtU0uTASXevfLMFfBeVCIIdcQhn/uBQsMTjBajdnAtanQlOcuihWh10PZ7+HWvc7NtBwP74w==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + }, + "dependencies": { + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + } + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz", + "integrity": "sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.15" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz", + "integrity": "sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.23.3.tgz", + "integrity": "sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.23.3.tgz", + "integrity": "sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-dynamic-import": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.23.3.tgz", + "integrity": "sha512-vTG+cTGxPFou12Rj7ll+eD5yWeNl5/8xvQvF08y5Gv3v4mZQoyFf8/n9zg4q5vvCWt5jmgymfzMAldO7orBn7A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz", + "integrity": "sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-export-namespace-from": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.23.3.tgz", + "integrity": "sha512-yCLhW34wpJWRdTxxWtFZASJisihrfyMOTOQexhVzA78jlU+dH7Dw+zQgcPepQ5F3C6bAIiblZZ+qBggJdHiBAg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.3.tgz", + "integrity": "sha512-X8jSm8X1CMwxmK878qsUGJRmbysKNbdpTv/O1/v0LuY/ZkZrng5WYiekYSdg9m09OTmDDUWeEDsTE+17WYbAZw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.23.3.tgz", + "integrity": "sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-json-strings": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.23.3.tgz", + "integrity": "sha512-H9Ej2OiISIZowZHaBwF0tsJOih1PftXJtE8EWqlEIwpc7LMTGq0rPOrywKLQ4nefzx8/HMR0D3JGXoMHYvhi0A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz", + "integrity": "sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-logical-assignment-operators": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.23.3.tgz", + "integrity": "sha512-+pD5ZbxofyOygEp+zZAfujY2ShNCXRpDRIPOiBmTO693hhyOEteZgl876Xs9SAHPQpcV0vz8LvA/T+w8AzyX8A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.23.3.tgz", + "integrity": "sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz", + "integrity": "sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz", + "integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.3.tgz", + "integrity": "sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz", + "integrity": "sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz", + "integrity": "sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.23.3.tgz", + "integrity": "sha512-xzg24Lnld4DYIdysyf07zJ1P+iIfJpxtVFOzX4g+bsJ3Ng5Le7rXx9KwqKzuyaUeRnt+I1EICwQITqc0E2PmpA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-transform-numeric-separator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.23.3.tgz", + "integrity": "sha512-s9GO7fIBi/BLsZ0v3Rftr6Oe4t0ctJ8h4CCXfPoEJwmvAPMyNrfkOOJzm6b9PX9YXcCJWWQd/sBF/N26eBiMVw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-transform-object-rest-spread": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.3.tgz", + "integrity": "sha512-VxHt0ANkDmu8TANdE9Kc0rndo/ccsmfe2Cx2y5sI4hu3AukHQ5wAu4cM7j3ba8B9548ijVyclBU+nuDQftZsog==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.23.3", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.23.3" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz", + "integrity": "sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20" + } + }, + "@babel/plugin-transform-optional-catch-binding": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.23.3.tgz", + "integrity": "sha512-LxYSb0iLjUamfm7f1D7GpiS4j0UAC8AOiehnsGAP8BEsIX8EOi3qV6bbctw8M7ZvLtcoZfZX5Z7rN9PlWk0m5A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + } + }, + "@babel/plugin-transform-optional-chaining": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.3.tgz", + "integrity": "sha512-zvL8vIfIUgMccIAK1lxjvNv572JHFJIKb4MWBz5OGdBQA0fB0Xluix5rmOby48exiJc987neOmP/m9Fnpkz3Tg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz", + "integrity": "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-private-methods": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.23.3.tgz", + "integrity": "sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-private-property-in-object": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.3.tgz", + "integrity": "sha512-a5m2oLNFyje2e/rGKjVfAELTVI5mbA0FeZpBnkOWWV7eSmKQ+T/XW0Vf+29ScLzSxX+rnsarvU0oie/4m6hkxA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz", + "integrity": "sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz", + "integrity": "sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.2" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz", + "integrity": "sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz", + "integrity": "sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz", + "integrity": "sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz", + "integrity": "sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz", + "integrity": "sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz", + "integrity": "sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz", + "integrity": "sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-unicode-property-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.23.3.tgz", + "integrity": "sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz", + "integrity": "sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-unicode-sets-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.23.3.tgz", + "integrity": "sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/preset-env": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.3.tgz", + "integrity": "sha512-ovzGc2uuyNfNAs/jyjIGxS8arOHS5FENZaNn4rtE7UdKMMkqHCvboHfcuhWLZNX5cB44QfcGNWjaevxMzzMf+Q==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.23.3", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.3", + "@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.23.3", + "@babel/plugin-syntax-import-attributes": "^7.23.3", + "@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.23.3", + "@babel/plugin-transform-async-generator-functions": "^7.23.3", + "@babel/plugin-transform-async-to-generator": "^7.23.3", + "@babel/plugin-transform-block-scoped-functions": "^7.23.3", + "@babel/plugin-transform-block-scoping": "^7.23.3", + "@babel/plugin-transform-class-properties": "^7.23.3", + "@babel/plugin-transform-class-static-block": "^7.23.3", + "@babel/plugin-transform-classes": "^7.23.3", + "@babel/plugin-transform-computed-properties": "^7.23.3", + "@babel/plugin-transform-destructuring": "^7.23.3", + "@babel/plugin-transform-dotall-regex": "^7.23.3", + "@babel/plugin-transform-duplicate-keys": "^7.23.3", + "@babel/plugin-transform-dynamic-import": "^7.23.3", + "@babel/plugin-transform-exponentiation-operator": "^7.23.3", + "@babel/plugin-transform-export-namespace-from": "^7.23.3", + "@babel/plugin-transform-for-of": "^7.23.3", + "@babel/plugin-transform-function-name": "^7.23.3", + "@babel/plugin-transform-json-strings": "^7.23.3", + "@babel/plugin-transform-literals": "^7.23.3", + "@babel/plugin-transform-logical-assignment-operators": "^7.23.3", + "@babel/plugin-transform-member-expression-literals": "^7.23.3", + "@babel/plugin-transform-modules-amd": "^7.23.3", + "@babel/plugin-transform-modules-commonjs": "^7.23.3", + "@babel/plugin-transform-modules-systemjs": "^7.23.3", + "@babel/plugin-transform-modules-umd": "^7.23.3", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.23.3", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.23.3", + "@babel/plugin-transform-numeric-separator": "^7.23.3", + "@babel/plugin-transform-object-rest-spread": "^7.23.3", + "@babel/plugin-transform-object-super": "^7.23.3", + "@babel/plugin-transform-optional-catch-binding": "^7.23.3", + "@babel/plugin-transform-optional-chaining": "^7.23.3", + "@babel/plugin-transform-parameters": "^7.23.3", + "@babel/plugin-transform-private-methods": "^7.23.3", + "@babel/plugin-transform-private-property-in-object": "^7.23.3", + "@babel/plugin-transform-property-literals": "^7.23.3", + "@babel/plugin-transform-regenerator": "^7.23.3", + "@babel/plugin-transform-reserved-words": "^7.23.3", + "@babel/plugin-transform-shorthand-properties": "^7.23.3", + "@babel/plugin-transform-spread": "^7.23.3", + "@babel/plugin-transform-sticky-regex": "^7.23.3", + "@babel/plugin-transform-template-literals": "^7.23.3", + "@babel/plugin-transform-typeof-symbol": "^7.23.3", + "@babel/plugin-transform-unicode-escapes": "^7.23.3", + "@babel/plugin-transform-unicode-property-regex": "^7.23.3", + "@babel/plugin-transform-unicode-regex": "^7.23.3", + "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.6", + "babel-plugin-polyfill-corejs3": "^0.8.5", + "babel-plugin-polyfill-regenerator": "^0.5.3", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + } + }, + "@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "@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 + }, + "@babel/runtime": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", + "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.14.0" + } + }, + "@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + } + }, + "@babel/traverse": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.3.tgz", + "integrity": "sha512-+K0yF1/9yR0oHdE0StHuEj3uTPzwwbrLGfNOndVJVV2TqA5+j3oljJUb4nmB954FLGjNem976+B+eDuLIjesiQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.3", + "@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.23.3", + "@babel/types": "^7.23.3", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "dependencies": { + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.3.tgz", + "integrity": "sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + } + }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "@eslint/eslintrc": { + "version": "1.4.1", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.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" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "@humanwhocodes/config-array": { + "version": "0.11.8", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "dev": true + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "dev": true + }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "requires": { + "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" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true + }, + "@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "requires": { + "@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" + } + }, + "@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "requires": { + "@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" + } + }, + "@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "requires": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + } + }, + "@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "requires": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + } + }, + "@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "requires": { + "jest-get-type": "^29.6.3" + } + }, + "@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "requires": { + "@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" + } + }, + "@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "requires": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + } + }, + "@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "requires": { + "@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" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "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" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "@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==", + "dev": true, + "requires": { + "@sinclair/typebox": "^0.27.8" + } + }, + "@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + } + }, + "@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "requires": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "requires": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + } + }, + "@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "requires": { + "@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" + } + }, + "@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "requires": { + "@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" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@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 + }, + "@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@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 + }, + "@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "requires": { + "@sinonjs/commons": "^3.0.0" + } + }, + "@types/babel__core": { + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.4.tgz", + "integrity": "sha512-mLnSC22IC4vcWiuObSRjrLd9XcBTGf59vUSoq2jkQDJ/QQ8PMI9rSuzE+aEV8karUMbskw07bKYoUJCKTUaygg==", + "dev": true, + "requires": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.7.tgz", + "integrity": "sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz", + "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==", + "dev": true, + "requires": { + "@babel/types": "^7.20.7" + } + }, + "@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/json5": { + "version": "0.0.29", + "dev": true + }, + "@types/node": { + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz", + "integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==", + "dev": true, + "requires": { + "undici-types": "~5.26.4" + } + }, + "@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true + }, + "@types/yargs": { + "version": "17.0.31", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.31.tgz", + "integrity": "sha512-bocYSx4DI8TmdlvxqGpVNXOgCNR1Jj0gNPhhAY+iz1rgKDAaYrAYdFYnhDV1IFuiuVc9HkOwyDcFxaTElF3/wg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "accepts": { + "version": "1.3.8", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "acorn": { + "version": "8.8.1", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "dev": true, + "requires": {} + }, + "aggregate-error": { + "version": "3.1.0", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "6.12.6", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-escapes": { + "version": "4.3.2", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "dev": true + } + } + }, + "ansi-regex": { + "version": "5.0.1", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" + }, + "argparse": { + "version": "2.0.1" + }, + "array-flatten": { + "version": "1.1.1" + }, + "array-includes": { + "version": "3.1.6", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + } + }, + "array.prototype.flat": { + "version": "1.3.1", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.flatmap": { + "version": "1.3.1", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + } + }, + "astral-regex": { + "version": "2.0.0", + "dev": true + }, + "available-typed-arrays": { + "version": "1.0.5", + "dev": true + }, + "babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "requires": { + "@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" + } + }, + "babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "requires": { + "@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" + }, + "dependencies": { + "istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "requires": { + "@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" + } + } + } + }, + "babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-plugin-polyfill-corejs2": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.6.tgz", + "integrity": "sha512-jhHiWVZIlnPbEUKSSNb9YoWcQGdlTLq7z1GHL4AjFxaoOUMuuEVJ+Y4pAaQUGOGk93YsVCKPbqbfw3m0SM6H8Q==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.4.3", + "semver": "^6.3.1" + } + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.8.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.6.tgz", + "integrity": "sha512-leDIc4l4tUgU7str5BWLS2h8q2N4Nf6lGZP6UrNDxdtfF2g69eJ5L0H7S8A5Ln/arfFAfHor5InAdZuIOwZdgQ==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.4.3", + "core-js-compat": "^3.33.1" + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.3.tgz", + "integrity": "sha512-8sHeDOmXC8csczMrYEOf0UTNa4yE2SxV5JGeT/LP1n0OYVDUUFPxG9vdk2AlDlIit4t+Kf0xCtpgXPBwnn/9pw==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.4.3" + } + }, + "babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "requires": { + "@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" + } + }, + "babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, + "balanced-match": { + "version": "1.0.2" + }, + "basic-auth": { + "version": "2.0.1", + "requires": { + "safe-buffer": "5.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2" + } + } + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + }, + "body-parser": { + "version": "1.20.1", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "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.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0" + } + } + }, + "brace-expansion": { + "version": "2.0.1", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "braces": { + "version": "3.0.2", + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.13" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "requires": { + "node-int64": "^0.4.0" + } + }, + "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==" + }, + "builtins": { + "version": "5.0.1", + "dev": true, + "requires": { + "semver": "^7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "requires": { + "streamsearch": "^1.1.0" + } + }, + "bytes": { + "version": "3.1.2" + }, + "call-bind": { + "version": "1.0.2", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001561", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001561.tgz", + "integrity": "sha512-NTt0DNoKe958Q0BE0j0c1V9jbUzhBxHIEJy7asmGrpE0yG63KTV7PLHPnK2E1O9RsQrQ081I3NLuXGS6zht3cw==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true + }, + "charenc": { + "version": "0.0.2" + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.3", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true + }, + "cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "dev": true + }, + "clean-stack": { + "version": "2.2.0", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-truncate": { + "version": "3.1.0", + "dev": true, + "requires": { + "slice-ansi": "^5.0.0", + "string-width": "^5.0.0" + } + }, + "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, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "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 + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + } + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true + }, + "collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true + }, + "color-convert": { + "version": "2.0.1", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "dev": true + }, + "colorette": { + "version": "2.0.19", + "dev": true + }, + "commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true + }, + "concat-map": { + "version": "0.0.1" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "content-disposition": { + "version": "0.5.4", + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.4" + }, + "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 + }, + "cookie": { + "version": "0.5.0" + }, + "cookie-parser": { + "version": "1.4.6", + "requires": { + "cookie": "0.4.1", + "cookie-signature": "1.0.6" + }, + "dependencies": { + "cookie": { + "version": "0.4.1" + } + } + }, + "cookie-signature": { + "version": "1.0.6" + }, + "copy-env-cli": { + "version": "1.0.0" + }, + "core-js-compat": { + "version": "3.33.2", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.33.2.tgz", + "integrity": "sha512-axfo+wxFVxnqf8RvxTzoAlzW4gRoacrHeoFlc9n0x50+7BEyZL/Rt3hicaED1/CEd7I6tPCPVUYcJwCMO5XUYw==", + "dev": true, + "requires": { + "browserslist": "^4.22.1" + } + }, + "cors": { + "version": "2.8.5", + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, + "create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "requires": { + "@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" + } + }, + "cross-spawn": { + "version": "7.0.3", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypt": { + "version": "0.0.2" + }, + "data-uri-to-buffer": { + "version": "4.0.0" + }, + "debug": { + "version": "4.3.4", + "requires": { + "ms": "2.1.2" + } + }, + "dedent": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", + "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "dev": true, + "requires": {} + }, + "deep-is": { + "version": "0.1.4", + "dev": true + }, + "deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true + }, + "define-properties": { "version": "1.1.4", "dev": true, "requires": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "depd": { + "version": "2.0.0" + }, + "destroy": { + "version": "1.2.0" + }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true + }, + "diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true + }, + "doctrine": { + "version": "3.0.0", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dotenv": { + "version": "16.0.3" + }, + "eastasianwidth": { + "version": "0.2.0", + "dev": true + }, + "ee-first": { + "version": "1.1.1" + }, + "electron-to-chromium": { + "version": "1.4.581", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.581.tgz", + "integrity": "sha512-6uhqWBIapTJUxgPTCHH9sqdbxIMPt7oXl0VcAL1kOtlU6aECdcMncCrX5Z7sHQ/invtrC9jUQUef7+HhO8vVFw==", + "dev": true + }, + "emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "dev": true + }, + "encodeurl": { + "version": "1.0.2" + }, + "entities": { + "version": "3.0.1" + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.21.1", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.4", + "is-array-buffer": "^3.0.1", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" + } + }, + "es-set-tostringtag": { + "version": "2.0.1", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + } + }, + "es-shim-unscopables": { + "version": "1.0.0", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-html": { + "version": "1.0.3" + }, + "escape-string-regexp": { + "version": "4.0.0", + "dev": true + }, + "eslint": { + "version": "8.32.0", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "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.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "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", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "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.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "eslint-config-prettier": { + "version": "8.6.0", + "dev": true, + "requires": {} + }, + "eslint-config-standard": { + "version": "17.0.0", + "dev": true, + "requires": {} + }, + "eslint-import-resolver-node": { + "version": "0.3.7", + "dev": true, + "requires": { + "debug": "^3.2.7", + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-module-utils": { + "version": "2.7.4", + "dev": true, + "requires": { + "debug": "^3.2.7" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-plugin-es": { + "version": "4.1.0", + "dev": true, + "requires": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + }, + "dependencies": { + "eslint-utils": { + "version": "2.1.0", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "dev": true + } + } + }, + "eslint-plugin-import": { + "version": "2.27.5", + "dev": true, + "requires": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", + "has": "^1.0.3", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", + "tsconfig-paths": "^3.14.1" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "debug": { + "version": "3.2.7", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "doctrine": { + "version": "2.1.0", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "minimatch": { + "version": "3.1.2", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "eslint-plugin-n": { + "version": "15.6.1", + "dev": true, + "requires": { + "builtins": "^5.0.1", + "eslint-plugin-es": "^4.1.0", + "eslint-utils": "^3.0.0", + "ignore": "^5.1.1", + "is-core-module": "^2.11.0", + "minimatch": "^3.1.2", + "resolve": "^1.22.1", + "semver": "^7.3.8" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } } }, - "depd": { - "version": "2.0.0" + "eslint-plugin-promise": { + "version": "6.1.1", + "dev": true, + "requires": {} }, - "destroy": { - "version": "1.2.0" + "eslint-scope": { + "version": "7.1.1", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } }, - "doctrine": { + "eslint-utils": { "version": "3.0.0", "dev": true, "requires": { - "esutils": "^2.0.2" + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "dev": true + } } }, - "dotenv": { - "version": "16.0.3" - }, - "eastasianwidth": { - "version": "0.2.0", - "dev": true - }, - "ee-first": { - "version": "1.1.1" - }, - "emoji-regex": { - "version": "9.2.2", + "eslint-visitor-keys": { + "version": "3.3.0", "dev": true }, - "encodeurl": { - "version": "1.0.2" - }, - "entities": { - "version": "3.0.1" - }, - "es-abstract": { - "version": "1.21.1", + "espree": { + "version": "9.4.1", "dev": true, "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.3", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.4", - "is-array-buffer": "^3.0.1", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.10", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.2", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trimend": "^1.0.6", - "string.prototype.trimstart": "^1.0.6", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.9" + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" } }, - "es-set-tostringtag": { - "version": "2.0.1", + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.4.0", "dev": true, "requires": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" + "estraverse": "^5.1.0" } }, - "es-shim-unscopables": { - "version": "1.0.0", + "esrecurse": { + "version": "4.3.0", "dev": true, "requires": { - "has": "^1.0.3" + "estraverse": "^5.2.0" } }, - "es-to-primitive": { - "version": "1.2.1", + "estraverse": { + "version": "5.3.0", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "dev": true + }, + "etag": { + "version": "1.8.1" + }, + "execa": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", + "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", "dev": true, "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" } }, - "escape-html": { - "version": "1.0.3" - }, - "escape-string-regexp": { - "version": "4.0.0", + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "dev": true }, - "eslint": { - "version": "8.32.0", + "expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", "dev": true, "requires": { - "@eslint/eslintrc": "^1.4.1", - "@humanwhocodes/config-array": "^0.11.8", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "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.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", - "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", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "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.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" + "@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" + } + }, + "express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.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" }, "dependencies": { - "brace-expansion": { - "version": "1.1.11", - "dev": true, + "debug": { + "version": "2.6.9", "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "ms": "2.0.0" } }, - "minimatch": { - "version": "3.1.2", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } + "ms": { + "version": "2.0.0" } } }, - "eslint-config-prettier": { - "version": "8.6.0", + "express-basic-auth": { + "version": "1.2.1", + "requires": { + "basic-auth": "^2.0.1" + } + }, + "express-handlebars": { + "version": "6.0.6", + "requires": { + "glob": "^8.0.2", + "graceful-fs": "^4.2.10", + "handlebars": "^4.7.7" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "dev": true + }, + "fastq": { + "version": "1.15.0", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, - "requires": {} + "requires": { + "bser": "2.1.1" + } }, - "eslint-config-standard": { - "version": "17.0.0", - "dev": true, - "requires": {} + "fetch-blob": { + "version": "3.2.0", + "requires": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + } }, - "eslint-import-resolver-node": { - "version": "0.3.7", + "file-entry-cache": { + "version": "6.0.1", "dev": true, "requires": { - "debug": "^3.2.7", - "is-core-module": "^2.11.0", - "resolve": "^1.22.1" + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.2.0", + "requires": { + "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" }, "dependencies": { "debug": { - "version": "3.2.7", - "dev": true, + "version": "2.6.9", "requires": { - "ms": "^2.1.1" + "ms": "2.0.0" } + }, + "ms": { + "version": "2.0.0" } } }, - "eslint-module-utils": { - "version": "2.7.4", + "find-up": { + "version": "5.0.0", "dev": true, "requires": { - "debug": "^3.2.7" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" } }, - "eslint-plugin-es": { - "version": "4.1.0", + "flat-cache": { + "version": "3.0.4", "dev": true, "requires": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" - }, - "dependencies": { - "eslint-utils": { - "version": "2.1.0", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "eslint-visitor-keys": { - "version": "1.3.0", - "dev": true - } + "flatted": "^3.1.0", + "rimraf": "^3.0.2" } }, - "eslint-plugin-import": { - "version": "2.27.5", + "flatted": { + "version": "3.2.7", + "dev": true + }, + "for-each": { + "version": "0.3.3", "dev": true, "requires": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "array.prototype.flatmap": "^1.3.1", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.7", - "eslint-module-utils": "^2.7.4", + "is-callable": "^1.1.3" + } + }, + "formdata-polyfill": { + "version": "4.0.10", + "requires": { + "fetch-blob": "^3.1.2" + } + }, + "forwarded": { + "version": "0.2.0" + }, + "fresh": { + "version": "0.5.2" + }, + "fs.realpath": { + "version": "1.0.0" + }, + "function-bind": { + "version": "1.1.1" + }, + "function.prototype.name": { + "version": "1.1.5", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, + "functions-have-names": { + "version": "1.2.3", + "dev": true + }, + "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 + }, + "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==", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.3", + "requires": { + "function-bind": "^1.1.1", "has": "^1.0.3", - "is-core-module": "^2.11.0", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.values": "^1.1.6", - "resolve": "^1.22.1", - "semver": "^6.3.0", - "tsconfig-paths": "^3.14.1" - }, - "dependencies": { - "brace-expansion": { - "version": "1.1.11", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "debug": { - "version": "3.2.7", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "doctrine": { - "version": "2.1.0", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "minimatch": { - "version": "3.1.2", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - } + "has-symbols": "^1.0.3" } }, - "eslint-plugin-n": { - "version": "15.6.1", + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "dev": true + }, + "get-symbol-description": { + "version": "1.0.0", "dev": true, "requires": { - "builtins": "^5.0.1", - "eslint-plugin-es": "^4.1.0", - "eslint-utils": "^3.0.0", - "ignore": "^5.1.1", - "is-core-module": "^2.11.0", - "minimatch": "^3.1.2", - "resolve": "^1.22.1", - "semver": "^7.3.8" - }, - "dependencies": { - "brace-expansion": { - "version": "1.1.11", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "minimatch": { - "version": "3.1.2", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "semver": { - "version": "7.3.8", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" } }, - "eslint-plugin-promise": { - "version": "6.1.1", + "glob": { + "version": "8.0.3", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "glob-parent": { + "version": "6.0.2", "dev": true, - "requires": {} + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.19.0", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } }, - "eslint-scope": { - "version": "7.1.1", + "globalthis": { + "version": "1.0.3", "dev": true, "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "define-properties": "^1.1.3" } }, - "eslint-utils": { - "version": "3.0.0", + "gopd": { + "version": "1.0.1", "dev": true, "requires": { - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "dev": true - } + "get-intrinsic": "^1.1.3" } }, - "eslint-visitor-keys": { - "version": "3.3.0", + "graceful-fs": { + "version": "4.2.10" + }, + "grapheme-splitter": { + "version": "1.0.4", "dev": true }, - "espree": { - "version": "9.4.1", - "dev": true, + "handlebars": { + "version": "4.7.7", "requires": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" } }, - "esquery": { - "version": "1.4.0", - "dev": true, + "has": { + "version": "1.0.3", "requires": { - "estraverse": "^5.1.0" + "function-bind": "^1.1.1" } }, - "esrecurse": { - "version": "4.3.0", + "has-bigints": { + "version": "1.0.2", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "dev": true + }, + "has-property-descriptors": { + "version": "1.0.0", "dev": true, "requires": { - "estraverse": "^5.2.0" + "get-intrinsic": "^1.1.1" } }, - "estraverse": { - "version": "5.3.0", - "dev": true - }, - "esutils": { - "version": "2.0.3", + "has-proto": { + "version": "1.0.1", "dev": true }, - "etag": { - "version": "1.8.1" + "has-symbols": { + "version": "1.0.3" }, - "execa": { - "version": "6.1.0", + "has-tostringtag": { + "version": "1.0.0", "dev": true, "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.1", - "human-signals": "^3.0.1", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^3.0.7", - "strip-final-newline": "^3.0.0" + "has-symbols": "^1.0.2" } }, - "express": { - "version": "4.18.2", + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "http-errors": { + "version": "2.0.0", "requires": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.1", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.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", + "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0" - } + "toidentifier": "1.0.1" } }, - "express-basic-auth": { - "version": "1.2.1", - "requires": { - "basic-auth": "^2.0.1" - } + "human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "dev": true }, - "express-handlebars": { - "version": "6.0.6", + "husky": { + "version": "8.0.3" + }, + "iconv-lite": { + "version": "0.4.24", "requires": { - "glob": "^8.0.2", - "graceful-fs": "^4.2.10", - "handlebars": "^4.7.7" + "safer-buffer": ">= 2.1.2 < 3" } }, - "fast-deep-equal": { - "version": "3.1.3", + "ignore": { + "version": "5.2.4", "dev": true }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "dev": true + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==" }, - "fast-levenshtein": { - "version": "2.0.6", - "dev": true + "import-fresh": { + "version": "3.3.0", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } }, - "fastq": { - "version": "1.15.0", + "import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", "dev": true, "requires": { - "reusify": "^1.0.4" + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" } }, - "fetch-blob": { - "version": "3.2.0", + "imurmurhash": { + "version": "0.1.4", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "dev": true + }, + "inflight": { + "version": "1.0.6", "requires": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" + "once": "^1.3.0", + "wrappy": "1" } }, - "file-entry-cache": { - "version": "6.0.1", + "inherits": { + "version": "2.0.4" + }, + "internal-slot": { + "version": "1.0.4", "dev": true, "requires": { - "flat-cache": "^3.0.4" + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "side-channel": "^1.0.4" } }, - "fill-range": { - "version": "7.0.1", + "ipaddr.js": { + "version": "1.9.1" + }, + "is-array-buffer": { + "version": "3.0.1", "dev": true, "requires": { - "to-regex-range": "^5.0.1" + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-typed-array": "^1.1.10" } }, - "finalhandler": { - "version": "1.2.0", + "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 + }, + "is-bigint": { + "version": "1.0.4", + "dev": true, "requires": { - "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" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0" - } + "has-bigints": "^1.0.1" } }, - "find-up": { - "version": "5.0.0", - "dev": true, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "binary-extensions": "^2.0.0" } }, - "flat-cache": { - "version": "3.0.4", + "is-boolean-object": { + "version": "1.1.2", "dev": true, "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" } }, - "flatted": { - "version": "3.2.7", + "is-buffer": { + "version": "1.1.6" + }, + "is-callable": { + "version": "1.2.7", "dev": true }, - "for-each": { - "version": "0.3.3", + "is-core-module": { + "version": "2.11.0", "dev": true, "requires": { - "is-callable": "^1.1.3" + "has": "^1.0.3" } }, - "formdata-polyfill": { - "version": "4.0.10", + "is-date-object": { + "version": "1.0.5", + "dev": true, "requires": { - "fetch-blob": "^3.1.2" + "has-tostringtag": "^1.0.0" } }, - "forwarded": { - "version": "0.2.0" - }, - "fresh": { - "version": "0.5.2" + "is-extglob": { + "version": "2.1.1" }, - "fs.realpath": { - "version": "1.0.0" + "is-fullwidth-code-point": { + "version": "4.0.0", + "dev": true }, - "function-bind": { - "version": "1.1.1" + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true }, - "function.prototype.name": { - "version": "1.1.5", - "dev": true, + "is-glob": { + "version": "4.0.3", "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" + "is-extglob": "^2.1.1" } }, - "functions-have-names": { - "version": "1.2.3", + "is-negative-zero": { + "version": "2.0.2", "dev": true }, - "get-intrinsic": { - "version": "1.1.3", + "is-number": { + "version": "7.0.0" + }, + "is-number-object": { + "version": "1.0.7", + "dev": true, "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "has-tostringtag": "^1.0.0" } }, - "get-stream": { - "version": "6.0.1", + "is-path-inside": { + "version": "3.0.3", "dev": true }, - "get-symbol-description": { - "version": "1.0.0", + "is-regex": { + "version": "1.1.4", "dev": true, "requires": { "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "has-tostringtag": "^1.0.0" } }, - "glob": { - "version": "8.0.3", + "is-shared-array-buffer": { + "version": "1.0.2", + "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "call-bind": "^1.0.2" } }, - "glob-parent": { - "version": "6.0.2", + "is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true + }, + "is-string": { + "version": "1.0.7", "dev": true, "requires": { - "is-glob": "^4.0.3" + "has-tostringtag": "^1.0.0" } }, - "globals": { - "version": "13.19.0", + "is-symbol": { + "version": "1.0.4", "dev": true, "requires": { - "type-fest": "^0.20.2" + "has-symbols": "^1.0.2" } }, - "globalthis": { - "version": "1.0.3", + "is-typed-array": { + "version": "1.1.10", "dev": true, "requires": { - "define-properties": "^1.1.3" + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" } }, - "gopd": { - "version": "1.0.1", + "is-weakref": { + "version": "1.0.2", "dev": true, "requires": { - "get-intrinsic": "^1.1.3" + "call-bind": "^1.0.2" } }, - "graceful-fs": { - "version": "4.2.10" + "isexe": { + "version": "2.0.0", + "dev": true }, - "grapheme-splitter": { - "version": "1.0.4", + "istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true }, - "handlebars": { - "version": "4.7.7", + "istanbul-lib-instrument": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz", + "integrity": "sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==", + "dev": true, "requires": { - "minimist": "^1.2.5", - "neo-async": "^2.6.0", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4", - "wordwrap": "^1.0.0" + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "dependencies": { + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } } }, - "has": { - "version": "1.0.3", + "istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, "requires": { - "function-bind": "^1.1.1" + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" } }, - "has-bigints": { - "version": "1.0.2", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "dev": true - }, - "has-property-descriptors": { - "version": "1.0.0", + "istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, "requires": { - "get-intrinsic": "^1.1.1" + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" } }, - "has-proto": { - "version": "1.0.1", - "dev": true - }, - "has-symbols": { - "version": "1.0.3" - }, - "has-tostringtag": { - "version": "1.0.0", + "istanbul-reports": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", + "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", "dev": true, "requires": { - "has-symbols": "^1.0.2" + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" } }, - "http-errors": { - "version": "2.0.0", + "jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" } }, - "human-signals": { - "version": "3.0.1", - "dev": true - }, - "husky": { - "version": "8.0.3" - }, - "iconv-lite": { - "version": "0.4.24", + "jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "dependencies": { + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "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" + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "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, + "requires": { + "path-key": "^3.0.0" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + } } }, - "ignore": { - "version": "5.2.4", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", + "jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", "dev": true, "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "@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" + } + }, + "jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "requires": { + "@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" } }, - "imurmurhash": { - "version": "0.1.4", - "dev": true - }, - "indent-string": { - "version": "4.0.0", - "dev": true - }, - "inflight": { - "version": "1.0.6", + "jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, "requires": { - "once": "^1.3.0", - "wrappy": "1" + "@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" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "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" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } } }, - "inherits": { - "version": "2.0.4" - }, - "internal-slot": { - "version": "1.0.4", + "jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", "dev": true, "requires": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "side-channel": "^1.0.4" + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" } }, - "ipaddr.js": { - "version": "1.9.1" - }, - "is-array-buffer": { - "version": "3.0.1", + "jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-typed-array": "^1.1.10" + "detect-newline": "^3.0.0" } }, - "is-bigint": { - "version": "1.0.4", + "jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", "dev": true, "requires": { - "has-bigints": "^1.0.1" + "@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" } }, - "is-boolean-object": { - "version": "1.1.2", + "jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "@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" } }, - "is-buffer": { - "version": "1.1.6" - }, - "is-callable": { - "version": "1.2.7", + "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==", "dev": true }, - "is-core-module": { - "version": "2.11.0", + "jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", "dev": true, "requires": { - "has": "^1.0.3" + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.3", + "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" } }, - "is-date-object": { - "version": "1.0.5", + "jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", "dev": true, "requires": { - "has-tostringtag": "^1.0.0" + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" } }, - "is-extglob": { - "version": "2.1.1", - "dev": true + "jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + } }, - "is-fullwidth-code-point": { - "version": "4.0.0", - "dev": true + "jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "requires": { + "@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" + } }, - "is-glob": { - "version": "4.0.3", + "jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", "dev": true, "requires": { - "is-extglob": "^2.1.1" + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" } }, - "is-negative-zero": { - "version": "2.0.2", - "dev": true + "jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "requires": {} }, - "is-number": { - "version": "7.0.0", + "jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", "dev": true }, - "is-number-object": { - "version": "1.0.7", + "jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", "dev": true, "requires": { - "has-tostringtag": "^1.0.0" + "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" } }, - "is-path-inside": { - "version": "3.0.3", - "dev": true - }, - "is-regex": { - "version": "1.1.4", + "jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" } }, - "is-shared-array-buffer": { - "version": "1.0.2", + "jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", "dev": true, "requires": { - "call-bind": "^1.0.2" + "@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" + } + }, + "jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "requires": { + "@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" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "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" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + } } }, - "is-stream": { - "version": "3.0.0", - "dev": true - }, - "is-string": { - "version": "1.0.7", + "jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", "dev": true, "requires": { - "has-tostringtag": "^1.0.0" + "@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" + }, + "dependencies": { + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } } }, - "is-symbol": { - "version": "1.0.4", + "jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dev": true, "requires": { - "has-symbols": "^1.0.2" + "@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" } }, - "is-typed-array": { - "version": "1.1.10", + "jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", "dev": true, "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" + "@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" + }, + "dependencies": { + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + } } }, - "is-weakref": { - "version": "1.0.2", + "jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", "dev": true, "requires": { - "call-bind": "^1.0.2" + "@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" } }, - "isexe": { - "version": "2.0.0", - "dev": true + "jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "requires": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } }, "js-sdsl": { "version": "4.2.0", "dev": true }, + "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 + }, "js-yaml": { "version": "4.1.0", "dev": true, @@ -5057,6 +12918,18 @@ "argparse": "^2.0.1" } }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "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 + }, "json-schema-traverse": { "version": "0.4.1", "dev": true @@ -5072,6 +12945,18 @@ "minimist": "^1.2.0" } }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, "levn": { "version": "0.4.1", "dev": true, @@ -5081,7 +12966,15 @@ } }, "lilconfig": { - "version": "2.0.6", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true + }, + "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 }, "linkify-it": { @@ -5091,22 +12984,32 @@ } }, "lint-staged": { - "version": "13.1.0", + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.2.3.tgz", + "integrity": "sha512-zVVEXLuQIhr1Y7R7YAWx4TZLdvuzk7DnmrsTNL0fax6Z3jrpFcas+vKbzxhhvp6TA55m1SQuWkpzI1qbfDZbAg==", "dev": true, "requires": { + "chalk": "5.2.0", "cli-truncate": "^3.1.0", - "colorette": "^2.0.19", - "commander": "^9.4.1", + "commander": "^10.0.0", "debug": "^4.3.4", - "execa": "^6.1.0", - "lilconfig": "2.0.6", - "listr2": "^5.0.5", + "execa": "^7.0.0", + "lilconfig": "2.1.0", + "listr2": "^5.0.7", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", - "object-inspect": "^1.12.2", + "object-inspect": "^1.12.3", "pidtree": "^0.6.0", "string-argv": "^0.3.1", - "yaml": "^2.1.3" + "yaml": "^2.2.2" + }, + "dependencies": { + "chalk": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", + "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", + "dev": true + } } }, "listr2": { @@ -5166,6 +13069,12 @@ "p-locate": "^5.0.0" } }, + "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 + }, "lodash.merge": { "version": "4.6.2", "dev": true @@ -5219,11 +13128,39 @@ }, "lru-cache": { "version": "6.0.0", - "dev": true, "requires": { "yallist": "^4.0.0" } }, + "make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "requires": { + "semver": "^7.5.3" + }, + "dependencies": { + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "requires": { + "tmpl": "1.0.5" + } + }, "markdown-it": { "version": "13.0.1", "requires": { @@ -5280,6 +13217,8 @@ }, "mimic-fn": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", "dev": true }, "minimatch": { @@ -5291,12 +13230,34 @@ "minimist": { "version": "1.2.7" }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "requires": { + "minimist": "^1.2.6" + } + }, "moment": { "version": "2.29.4" }, "ms": { "version": "2.1.2" }, + "multer": { + "version": "1.4.5-lts.1", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz", + "integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==", + "requires": { + "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" + } + }, "natural-compare": { "version": "1.4.0", "dev": true @@ -5318,12 +13279,90 @@ "formdata-polyfill": "^4.0.10" } }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", + "dev": true + }, + "nodemon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.2.tgz", + "integrity": "sha512-9qIN2LNTrEzpOPBaWHTm4Asy1LxXLSickZStAQ4IZe7zsoIpD/A7LWxhZV3t4Zu352uBcqVnRsDXSMR2Sc3lTA==", + "requires": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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==" + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "requires": { + "abbrev": "1" + } + }, "normalize-path": { - "version": "3.0.0", - "dev": true + "version": "3.0.0" }, "npm-run-path": { "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", "dev": true, "requires": { "path-key": "^4.0.0" @@ -5331,6 +13370,8 @@ "dependencies": { "path-key": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", "dev": true } } @@ -5339,7 +13380,9 @@ "version": "4.1.1" }, "object-inspect": { - "version": "1.12.2" + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==" }, "object-keys": { "version": "1.1.1", @@ -5378,6 +13421,8 @@ }, "onetime": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", "dev": true, "requires": { "mimic-fn": "^4.0.0" @@ -5416,6 +13461,12 @@ "aggregate-error": "^3.0.0" } }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, "parent-module": { "version": "1.0.1", "dev": true, @@ -5423,6 +13474,18 @@ "callsites": "^3.0.0" } }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@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" + } + }, "parseurl": { "version": "1.3.3" }, @@ -5445,14 +13508,73 @@ "path-to-regexp": { "version": "0.1.7" }, - "picomatch": { - "version": "2.3.1", + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", "dev": true }, + "picomatch": { + "version": "2.3.1" + }, "pidtree": { "version": "0.6.0", "dev": true }, + "pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + } + } + }, "prelude-ls": { "version": "1.2.1", "dev": true @@ -5461,6 +13583,35 @@ "version": "2.8.3", "dev": true }, + "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==", + "dev": true, + "requires": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, "proxy-addr": { "version": "2.0.7", "requires": { @@ -5468,10 +13619,21 @@ "ipaddr.js": "1.9.1" } }, + "pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" + }, "punycode": { "version": "2.2.0", "dev": true }, + "pure-rand": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", + "integrity": "sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==", + "dev": true + }, "qs": { "version": "6.11.0", "requires": { @@ -5499,6 +13661,42 @@ "unpipe": "1.0.0" } }, + "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 + }, + "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 + }, + "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==", + "dev": true, + "requires": { + "regenerate": "^1.4.2" + } + }, + "regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", + "dev": true + }, + "regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.4" + } + }, "regexp.prototype.flags": { "version": "1.4.3", "dev": true, @@ -5512,6 +13710,43 @@ "version": "3.2.0", "dev": true }, + "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==", + "dev": true, + "requires": { + "@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" + } + }, + "regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true + } + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, "resolve": { "version": "1.22.1", "dev": true, @@ -5521,10 +13756,33 @@ "supports-preserve-symlinks-flag": "^1.0.0" } }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, "resolve-from": { "version": "4.0.0", "dev": true }, + "resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true + }, "restore-cursor": { "version": "3.1.0", "dev": true, @@ -5639,7 +13897,9 @@ "version": "2.1.2" }, "semver": { - "version": "6.3.0", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true }, "send": { @@ -5711,6 +13971,36 @@ "version": "3.0.7", "dev": true }, + "simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "requires": { + "semver": "^7.5.3" + }, + "dependencies": { + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, "slice-ansi": { "version": "5.0.0", "dev": true, @@ -5728,13 +14018,61 @@ "source-map": { "version": "0.6.1" }, + "source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, "statuses": { "version": "2.0.1" }, + "streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" + }, "string-argv": { "version": "0.3.1", "dev": true }, + "string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } + }, "string-width": { "version": "5.1.2", "dev": true, @@ -5788,6 +14126,8 @@ }, "strip-final-newline": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "dev": true }, "strip-json-comments": { @@ -5805,6 +14145,52 @@ "version": "1.0.0", "dev": true }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "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" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, "text-table": { "version": "0.2.0", "dev": true @@ -5813,9 +14199,20 @@ "version": "2.3.8", "dev": true }, + "tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "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 + }, "to-regex-range": { "version": "5.0.1", - "dev": true, "requires": { "is-number": "^7.0.0" } @@ -5823,6 +14220,14 @@ "toidentifier": { "version": "1.0.1" }, + "touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "requires": { + "nopt": "~1.0.10" + } + }, "tsconfig-paths": { "version": "3.14.1", "dev": true, @@ -5844,6 +14249,12 @@ "prelude-ls": "^1.2.1" } }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, "type-fest": { "version": "0.20.2", "dev": true @@ -5864,6 +14275,11 @@ "is-typed-array": "^1.1.9" } }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + }, "uc.micro": { "version": "1.0.6" }, @@ -5881,9 +14297,58 @@ "which-boxed-primitive": "^1.0.2" } }, + "undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" + }, + "undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "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 + }, + "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, + "requires": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + } + }, + "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 + }, + "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 + }, "unpipe": { "version": "1.0.0" }, + "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, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, "uri-js": { "version": "4.4.1", "dev": true, @@ -5894,9 +14359,29 @@ "utils-merge": { "version": "1.0.1" }, + "v8-to-istanbul": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.3.tgz", + "integrity": "sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + } + }, "vary": { "version": "1.1.2" }, + "walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "requires": { + "makeerror": "1.0.12" + } + }, "web-streams-polyfill": { "version": "3.2.1" }, @@ -5931,7 +14416,9 @@ } }, "word-wrap": { - "version": "1.2.3", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true }, "wordwrap": { @@ -5968,15 +14455,83 @@ "wrappy": { "version": "1.0.2" }, + "write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + }, "xml": { "version": "1.0.1" }, - "yallist": { - "version": "4.0.0", + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true }, + "yallist": { + "version": "4.0.0" + }, "yaml": { - "version": "2.2.1", + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "dev": true + }, + "yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "dependencies": { + "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 + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + } + } + }, + "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 }, "yocto-queue": { diff --git a/package.json b/package.json index 9094d840..369d01f2 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "scripts": { "prepare": "husky install", "start": "node index.js", - "test": "echo \"Error: no test specified\" && exit 1", + "test": "jest --coverage", "postinstall": "copy-env-cli", "lint": "eslint lib/. && prettier --check lib/.", "lint:fix": "eslint lib/. --fix && prettier --write lib/." @@ -39,7 +39,7 @@ "cors": "^2.8.4", "debug": "^4.3.4", "dotenv": "^16.0.3", - "express": "^4.16.3", + "express": "^4.18.2", "express-basic-auth": "^1.1.5", "express-handlebars": "^6.0.6", "glob": "^8.0.3", @@ -47,18 +47,24 @@ "markdown-it": "^13.0.1", "md5": "^2.3.0", "moment": "^2.29.4", + "multer": "^1.4.5-lts.1", "node-fetch": "^3.3.0", + "nodemon": "^3.0.2", "queue-promise": "^2.2.1", "rss-generator": "^0.0.3" }, "devDependencies": { + "@babel/core": "^7.23.3", + "@babel/preset-env": "^7.23.3", + "babel-jest": "^29.7.0", "eslint": "^8.32.0", "eslint-config-prettier": "^8.6.0", "eslint-config-standard": "^17.0.0", "eslint-plugin-import": "^2.27.5", "eslint-plugin-n": "^15.6.1", "eslint-plugin-promise": "^6.1.1", - "lint-staged": "^13.1.0", + "jest": "^29.7.0", + "lint-staged": "^13.2.3", "prettier": "^2.8.3" }, "lint-staged": { diff --git a/projectDocs/Pitch Document.pdf b/projectDocs/Pitch Document.pdf new file mode 100644 index 00000000..6e5c5b1a Binary files /dev/null and b/projectDocs/Pitch Document.pdf differ diff --git a/projectDocs/meeting-notes/11-04-2023.md b/projectDocs/meeting-notes/11-04-2023.md new file mode 100644 index 00000000..252b1074 --- /dev/null +++ b/projectDocs/meeting-notes/11-04-2023.md @@ -0,0 +1,45 @@ +# Meeting Notes + +**Date:** 4th November, 2023 +**Location:** Brisa study room + +## Attendees + +- Aditya +- Smruthi +- Kashish +- Ever +- Enze +- Justin +- Jay + +## Agenda + +- Discuss warm-up assignment issues. +- Clarify communication responsibilities. +- Emphasize open communication and mutual assistance. +- Group meetings every 2 days for 10-15 minutes. + - Agenda: Bottlenecks and updates; communicate if unable to attend. +- Splitting work discussion (page-wise or technology-wise). + +## Notes + +- Discussed warm-up assignment challenges. +- Clarified communication responsibilities for assigned tasks. +- Emphasized the importance of open communication and mutual assistance. +- Scheduled group meetings every 2 days for 10-15 minutes to discuss bottlenecks and updates. +- Agreed to split work, with further discussion on approach after the ideation phase. +- Ideation: + - Explored Fediverse issues and checked existing issues. + - Considered ideas like Pictionary on social media, a bot for generating pictures or riddles, openAI/dallE API requests, summarizer bot, llama 2, message/notification scheduling, delayed replies, and more. + - Discussed enhancements for Rattibha and Shuttlecraft's P2P Single User Server. + - Introduced [Postmarks](https://github.com/ckolderup/postmarks). +- Decided to rank all ideas and report encountered issues during the ranking process. + +## Next Steps + +- Explore and evaluate ideation proposals. +- Rank and provide feedback on the presented ideas. +- Address any encountered issues during the ranking process. + +**Author:** Kashish Jain diff --git a/projectDocs/meeting-notes/11-05-2023.md b/projectDocs/meeting-notes/11-05-2023.md new file mode 100644 index 00000000..89512653 --- /dev/null +++ b/projectDocs/meeting-notes/11-05-2023.md @@ -0,0 +1,52 @@ +# Meeting Notes + +**Date:** 5th November, 2023 +**Location:** Online + +## Attendees + +- Kashish +- Aditya +- Smruthi +- Ever +- Justin +- Jay +- Enze + +## Agenda + +1. **Introduction** + + - Leaning towards solving some issues for [Shuttlecraft](https://github.com/benbrown/shuttlecraft) for the project idea. + +2. **Pitch Preparation** + + - We are going to use a slide deck for the pitch. + +3. **Issues to Work On** + + - [Issue #100](https://github.com/benbrown/shuttlecraft/issues/100) + - [Issue #110](https://github.com/benbrown/shuttlecraft/issues/110) + - [Issue #29](https://github.com/benbrown/shuttlecraft/issues/29) + - [Issue #76](https://github.com/benbrown/shuttlecraft/issues/76) + +4. **Slide Deck Structure** + + - Title slide + - Statement of purpose - Aditya, Kashish + - User persona 1 - Justin + - User persona 2 - Enze + - Risks and rabbit holes - Jay, Smruthi + - Fat-marker sketches/wireframes - Ever + - Project roadmap + - Thank you! + - Q&A + +5. **Statement of Purpose** + - Why are we using Shuttlecraft? + - Most pertinent issues to complete in a given timeframe + - Why we chose these issues + +## Closing Notes + +None diff --git a/projectDocs/meeting-notes/11-11-2023.md b/projectDocs/meeting-notes/11-11-2023.md new file mode 100644 index 00000000..afc58f9e --- /dev/null +++ b/projectDocs/meeting-notes/11-11-2023.md @@ -0,0 +1,42 @@ +# Meeting notes + +**Date:** 11 November, 2023 +**Location:** Online + +## Attendees + +- Kashish Jain +- Smruthi Gowtham +- Jay Yi Yang +- Justin Nguyen +- Aditya Mandke + +## Agenda + +- Discuss next steps before the lecture on November 14, 2023. +- Divide tasks among us + +## Pending tasks + +1. Test Cases +2. CI/CD pipeline +3. Slides +4. Setting up the agile platform (Jira or something) +5. Coupling Example using JavaScript + +## Work division + +1. Test Cases: Justin and Ever +2. CI/CD Pipeline: Kashish +3. Slides: Aditya +4. Setting up the agile platform: Smruthi +5. Coupling Example: Jay +6. Understand the code base: Everyone + +## Next steps + +1. Complete the tasks mentioned above by November 12, 2023 +2. Meet on November 13 regarding updates on the above. +3. Refactor the code by November 15, 2023 + +**Author:** Aditya Mandke diff --git a/projectDocs/meeting-notes/11-15-2023.md b/projectDocs/meeting-notes/11-15-2023.md new file mode 100644 index 00000000..6a1f0248 --- /dev/null +++ b/projectDocs/meeting-notes/11-15-2023.md @@ -0,0 +1,53 @@ +# Meeting Notes + +**Date:** 15 November, 2023 +**Location:** Online + +## Attendees + +- Kashish Jain +- Smruthi Gowtham +- Jay Yi Yang +- Justin Nguyen +- Aditya Mandke +- Ever + +## Pending Tasks + +- Get it running locally first +- Clean git structures +- Write unit tests +- High level functional diagram +- Write coding rules +- One iteration of refactoring +- Issues +- Slides (PPT for coupling) +- Questions for midterm +- Deciding static code analysis tool + +## Task division and ownership + +- Justin: Tests +- Jay: Routes +- Aditya: Index.js, App.js, remainder files, Clean repo files +- Smruthi: Lib +- Kashish: Lib +- Ever: Lib +- Enze: HTML, CSS + +## Deadline + +17th November 2023 + +## Side notes + +- CSS needs to be changed (excessive use of divs) +- Jay gave a demo of running the project locally + +## Meeting outcomes + +- Static code analysis tool: **Deepscan** +- Code coverage: aim for 75% +- Created coding standards document: https://docs.google.com/document/d/1SbdCsNVItytVbgHE5-8_ebth-mmNxH1jKp5L7uggWNI/edit + +**Author:** Smruthi Gowtham diff --git a/projectDocs/meeting-notes/12-02-2023.md b/projectDocs/meeting-notes/12-02-2023.md new file mode 100644 index 00000000..944b6df3 --- /dev/null +++ b/projectDocs/meeting-notes/12-02-2023.md @@ -0,0 +1,34 @@ +# Meeting Notes + +**Date:** 2nd December, 2023 +**Location:** Online + +## Attendees + +- Kashish +- Smruthi +- Jay +- Justin +- Enze +- Ever + +## Things Discussed + +- Current UI is too simple, should make the UI better (add it as an issue) +- Reduce the current scope, mainly focus on the the view/upate account issue, the password issue and better UI now +- Discuss the test coverage, aiming at a coverage of 50% (or 60% if possible), who adds a new feature should also makes a unit test (maybe TDD) +- Discuss the local-first issue, test if we can follow others and see posts from others +- Other things like the meaning of add link, clean the repo and so on +- Set tasks and goals for until Monday, agree on having a meeting every two days + +## Task Distribution + +- Better UI: Jay, Aditya +- Finish account feature: Ever, Enze +- Add more tests: Justin +- Password issue: Kashish, Smruthi +- Other tasks: clean the repo, edit readme.md and changelog.md, use const file + +## Deadline + +Dec 4, 2023 diff --git a/projectDocs/meeting-notes/12-06-2023.md b/projectDocs/meeting-notes/12-06-2023.md new file mode 100644 index 00000000..eb5bbe18 --- /dev/null +++ b/projectDocs/meeting-notes/12-06-2023.md @@ -0,0 +1,56 @@ +# Meeting Notes + +**Date:** 6th December, 2023 +**Location:** Online + +## Attendees + +- Aditya +- Jay +- Justin +- Smruthi +- Kashish +- Ever +- Enze + +## Agenda + +- UI Work Discussion +- Code Issues and Resolution +- Create Login Interface Redesign +- Testing Strategy and Coverage +- Code Refactoring and Documentation + +## Notes + +- **UI Work Discussion:** + + - Aditya and Jay addressed UI issues. + - Messages not showing in the latest commit; ongoing diagnosis. + +- **Code Issues and Resolution:** + + - Messages composer issues identified. + - Comparison of code for issue resolution. + +- **Create Login Interface Redesign:** + + - Smruthi and Kashish redesigned authentication workflow. + - Added create and login UI, removed external dependencies. + - Added logout functionality. + +- **Testing Strategy and Coverage:** + + - Justin discussed current testing status. + - Goal is to reach 60% coverage; 82 tests currently. + +- **Code Refactoring and Documentation:** + - Work distribution discussed. + - Code freeze tonight; changes merged by EOD. + +## Next Steps + +- Complete code freeze tasks. +- Prepare for meeting on 12/13/2023. + +**Author:** Aditya Mandke diff --git a/projectDocs/meeting-notes/12-09-2023.md b/projectDocs/meeting-notes/12-09-2023.md new file mode 100644 index 00000000..582b3cc6 --- /dev/null +++ b/projectDocs/meeting-notes/12-09-2023.md @@ -0,0 +1,65 @@ +# Meeting Notes + +**Date:** 9th December, 2023 +**Location:** Online + +## Attendees + +- Justin +- Aditya +- Ever +- Jay +- Kashish +- Enze + +## Agenda + +- Discuss individual updates +- Assignment for the final demo and presentation +- Decide final scope + +## Notes + +**Kashish and Smruthi** + +- Fixed bug with username on Windows +- Implemented logout functionality +- Main create account functionality has to be moved from index.js + - We want people to create an account after the server is booted +- Implemented delete user story + +**Aditya and Jay** + +- Added mock data to UI +- Made CSS changes to make UI look better +- Shared usernames with each other + +**Justin** + +- Continuing work on tests +- Increased code coverage for `account.js` + +**Ever** + +- Made a rough sketch of Miro board +- Uploaded documents to the repository +- Had some questions about how to test with Glitch + +**Enze** + +- Had a question about a Glitch error but didn't have a screenshot ready at that time + +### Issues to Address + +- All the messages show up on the left side for Kashish and Aditya, but they're okay for Justin. +- Kashish sees Compose box when sending messages. +- The latest message shows up at the top instead of the bottom for Aditya and Kashish. +- Fix handlebars files + +## Next Steps + +- Address the identified issues +- Complete assignments for the final demo and presentation +- Decide on the final scope for the project + +**Author:** Justin diff --git a/projectDocs/meeting-notes/12-11-2023.md b/projectDocs/meeting-notes/12-11-2023.md new file mode 100644 index 00000000..1824c18e --- /dev/null +++ b/projectDocs/meeting-notes/12-11-2023.md @@ -0,0 +1,66 @@ +# Meeting Notes + +**Date:** 11th December, 2023 +**Location:** Online + +## Attendees + +- Aditya +- Jay +- Justin +- Smruthi +- Kashish +- Ever +- Enze + +## Agenda + +- Discuss all updates since last meeting +- Give demos of all work done +- Discuss any issues +- Go through the evaluation rubric +- Divide work from the evaluation rubric document +- Wrap up by tomorrow + +## Notes + +- **Aditya and Jay Discuss UI Work:** + + - Messages not showing in the latest commit; Aditya diagnosing the issue. + - Messages composer looks off; issue with the composer. + - Discussion on why the issue is being created. + - Justin compared Aditya's code to the working one on his side. + - Aditya, Jay, and Justin plan to discuss the problem after this meeting. + +- **Smruthi and Kashish Discuss Create Login Interface:** + + - Redesigned authentication workflow and architecture. + - Added create and login UI. + - Removed the external dependency of 'express-basic-auth.' + - Added logout functionality. + +- **Ever and Enze Discuss Their Changes:** + + - They will send all their changes in the Slack channel. + +- **Justin Discusses Testing:** + + - Current test coverage is 40%. + - Goal is to reach 60%. + - Currently, there are 82 tests. + +- **Work Distribution and Tasks:** + + - Add the login-create user board to Miro - Task for Kashish. + - Discuss work distribution for code refactoring. + - Kashish, Aditya, Smruthi, and Enze work on documentation. + - Justin and Enze work on Testing. + - Jay works on code/repo cleaning. + - Code freeze is tonight; everyone gets their changes merged by EOD. + +- **Meeting on 12/13/2023 Agenda:** + + - Go through the code and working to ensure everyone is on the same page. + - Any end moment requirements we might have missed. + +**Author:** Kasish Jain diff --git a/projectDocs/meeting-notes/12-12-2023.md b/projectDocs/meeting-notes/12-12-2023.md new file mode 100644 index 00000000..d6d238d8 --- /dev/null +++ b/projectDocs/meeting-notes/12-12-2023.md @@ -0,0 +1,39 @@ +# Meeting Notes + +**Date:** 12th December, 2023 +**Location:** Online + +## Issues on Glitch + +- Justin unable to create Glitch instance +- Messaging not working on Glitch anymore - high priority issue + - Aditya, with the older code, can send messages, but Kashish, with the newer code, is unable to send messages. + - Decision: Run Glitch for every snapshot of the code after each commit to find the point of failure. + - Checked all commits + - Pinpointed a possible problematic commit - main branch not rebased. + - Reverted the commits. +- Boost, reply, etc. options not appearing for Aditya on posting + +## Documentation + +- Internal deadline for documentation: Thursday. +- Pitch document done +- Meeting notes done. +- Pipeline document - Kashish +- Raw Research and Ideation Materials - TODO +- Testing document - Justin. +- ADR, Sys design - 13th December meeting. +- UI/UX document - Aditya and Jay. + +## Miro Board Improvements + +- UI improvements not updated. +- Architecture diagram - needs to have ActivityPub and be less oversimplified. + +## Code Management + +- Closed unnecessary PRs. +- Solved Enze's merge conflicts. +- Pushed LoginUI PR. + +**Author:** Smruthi diff --git a/projectDocs/wireframes/images/index-hi.png b/projectDocs/wireframes/images/index-hi.png new file mode 100644 index 00000000..d7339b73 Binary files /dev/null and b/projectDocs/wireframes/images/index-hi.png differ diff --git a/projectDocs/wireframes/images/index-low.png b/projectDocs/wireframes/images/index-low.png new file mode 100644 index 00000000..5af42428 Binary files /dev/null and b/projectDocs/wireframes/images/index-low.png differ diff --git a/projectDocs/wireframes/images/msg-hi.png b/projectDocs/wireframes/images/msg-hi.png new file mode 100644 index 00000000..394d050c Binary files /dev/null and b/projectDocs/wireframes/images/msg-hi.png differ diff --git a/projectDocs/wireframes/images/msg-low.png b/projectDocs/wireframes/images/msg-low.png new file mode 100644 index 00000000..5eeee118 Binary files /dev/null and b/projectDocs/wireframes/images/msg-low.png differ diff --git a/projectDocs/wireframes/images/private-hi.png b/projectDocs/wireframes/images/private-hi.png new file mode 100644 index 00000000..d6e2a493 Binary files /dev/null and b/projectDocs/wireframes/images/private-hi.png differ diff --git a/projectDocs/wireframes/images/private-low.png b/projectDocs/wireframes/images/private-low.png new file mode 100644 index 00000000..df9ffdea Binary files /dev/null and b/projectDocs/wireframes/images/private-low.png differ diff --git a/projectDocs/wireframes/images/send-msg-hi.png b/projectDocs/wireframes/images/send-msg-hi.png new file mode 100644 index 00000000..5fbe615f Binary files /dev/null and b/projectDocs/wireframes/images/send-msg-hi.png differ diff --git a/projectDocs/wireframes/images/send-msg-low.png b/projectDocs/wireframes/images/send-msg-low.png new file mode 100644 index 00000000..a7fe5984 Binary files /dev/null and b/projectDocs/wireframes/images/send-msg-low.png differ diff --git a/public/.DS_Store b/public/.DS_Store deleted file mode 100644 index 68c73466..00000000 Binary files a/public/.DS_Store and /dev/null differ diff --git a/public/app.js b/public/app.js index 776bdd03..ef386795 100644 --- a/public/app.js +++ b/public/app.js @@ -2,7 +2,6 @@ const fetch = (url, type, payload = undefined) => { return new Promise((resolve, reject) => { const Http = new XMLHttpRequest(); Http.open(type, url); - // TODO: should be a parameter Http.setRequestHeader('Content-Type', 'application/json;charset=UTF-8'); Http.send(payload); @@ -196,7 +195,9 @@ const app = { const inReplyTo = document.getElementById('inReplyTo'); const to = document.getElementById('to'); const editOf = document.getElementById('editOf'); - + const canReply = document.getElementById('canReply').checked; + const canBoost = document.getElementById('canBoost').checked; + const canFave = document.getElementById('canFave').checked; const form = document.getElementById('composer_form'); form.disabled = true; @@ -209,7 +210,10 @@ const app = { cw: cw.value, inReplyTo: inReplyTo.value, to: to.value, - editOf: editOf ? editOf.value : null + editOf: editOf ? editOf.value : null, + canReply, + canBoost, + canFave }) ) .then(newHtml => { diff --git a/public/css/constants.css b/public/css/constants.css new file mode 100644 index 00000000..b2e1df3f --- /dev/null +++ b/public/css/constants.css @@ -0,0 +1,14 @@ +:root { + --background: #f9f9f9; /* Light gray background */ + --text: #333; /* Dark text color */ + --link: #1da1f2; /* Twitter blue */ + --secondary: #666; /* Dimmed secondary text */ + --tertiary: #e5e5e5; /* Light gray for tertiary elements */ + --contrast: #555; /* Dark gray for contrast */ + --separator: #1da1f2; /* Twitter blue for separators */ + --header: #e0e0e0; + --shade: rgba(249, 249, 249, 0.25); /* Slight shade for depth */ + --highlight: #888; /* Medium gray for highlights */ + --accent: #e50b76; /* Pink accent */ + --authentication-color: rgb(8, 0, 115); /* Twitter blue for authentication */ +} diff --git a/public/css/content.css b/public/css/content.css new file mode 100644 index 00000000..6694a574 --- /dev/null +++ b/public/css/content.css @@ -0,0 +1,74 @@ +@import url('./constants.css'); + +#content { + padding-bottom: 3rem; +} + +#content.nonav { + padding-bottom: 0; +} + +#content { + flex-grow: 1; + flex-shrink: 1; + overflow-y: auto; +} + +.content { + font-size: medium; + padding-bottom: 2px; +} +.activity .content { + padding-left: calc(50px + 1rem); +} + +.content_warning { + /* padding: 0.5rem 1rem; */ + font-size: smaller; +} + +.content_warning .tools { + flex-grow: 1; + text-align: right; + /* padding-right: 1rem; */ +} + +.content_warning .tools a { + margin: 0px auto; + padding: 0.25rem 1rem; + border-radius: 4px; + background: var(--shade); + text-decoration: none; +} + +.content .tools { + flex-grow: 1; +} +.content .tools div { + display: inline-block; +} +.content .tools button { + font-size: 1rem; + background: none; + border: none; + padding: 0; + margin-top: 2rem; + margin-right: 0.5rem; +} +/* .content .tools button.active { background: var(--highlight); } */ +.content .tools button .active { + display: none; +} +.content .tools button.active .active { + display: block; +} +.content .tools button.active .inactive { + display: none; +} + + +#content { + padding-left: 5%; + padding-right: 5%; + padding-top: 10px; +} diff --git a/public/css/main.css b/public/css/main.css index c3d50129..9a5878f2 100644 --- a/public/css/main.css +++ b/public/css/main.css @@ -1,116 +1,110 @@ body { - background: #F0F0f0; - color: #333; - font-size: 18px; + background: #f0f0f0; + color: #333; + font-size: 18px; } #wrapper { - display: flex; - width: 100%; - flex-direction: row; - gap: 0; + display: flex; + width: 100%; + flex-direction: row; + gap: 0; } #main { - height: 100vh; - overflow-y: scroll; - flex-grow: 1; - padding-bottom: 100px; + height: 100vh; + overflow-y: scroll; + flex-grow: 1; + padding-bottom: 100px; } -#content { - display: flex; - flex-direction: column; - gap: 2rem; +#content { + display: flex; + flex-direction: column; + gap: 2rem; } - -a { color: #8c8dff; } +a { + color: #8c8dff; +} .stream { - width: 100%; - margin: 0px auto; - max-width: 40rem; - text-overflow: ellipsis; - overflow-x: hidden; + width: 100%; + margin: 0px auto; + max-width: 40rem; + text-overflow: ellipsis; + overflow-x: hidden; } .activity { - border-top: 1px solid #393f4f; - background: #FFF; - padding: 1rem; + border-top: 1px solid #393f4f; + background: #fff; + padding: 1rem; } .activity .header { - display: flex; - flex-direction: row; - gap: 1rem; + display: flex; + flex-direction: row; + gap: 1rem; } .activity .header .avatar { - height: 50px; - width: 50px; + height: 50px; + width: 50px; } .activity .attachment img { - max-width: 100%; + max-width: 100%; } - .follow_box { - padding: 1rem; + padding: 1rem; } .follow_box p { - margin: 0; + margin: 0; } - - - .profileHeader { - height: 150px; - /* background: #111122; */ + height: 150px; + /* background: #111122; */ } .profileHeader img { - object-fit: cover; - height: 150px; - width: 100%; + object-fit: cover; + height: 150px; + width: 100%; } .profile { - /* background: #333344; */ + /* background: #333344; */ } - .profileToolbar { - padding: 1rem; - display: flex; + padding: 1rem; + display: flex; } .profileToolbar .avatarLink { - flex-grow: 0; - margin-top: calc(-50px - 1rem); + flex-grow: 0; + margin-top: calc(-50px - 1rem); } .profileToolbar .avatar { - width: 110px; - height: 110px; - border: 5px solid #333344; + width: 110px; + height: 110px; + border: 5px solid #333344; } .profileToolbar .tools { - text-align: right; - flex-grow: 1; + text-align: right; + flex-grow: 1; } - .profileBody { - padding: 0 1rem 1rem; + padding: 0 1rem 1rem; } .profileBody .author { - font-size: 1.25rem; - margin-bottom: 0.25rem; + font-size: 1.25rem; + margin-bottom: 0.25rem; } - diff --git a/public/css/secret.css b/public/css/secret.css index 9dff6229..a49d3e3e 100644 --- a/public/css/secret.css +++ b/public/css/secret.css @@ -1,903 +1,1100 @@ -:root { - --background: #ccc; - --text: #333333; - --link: #00018c; - --secondary: #ccc; - --tertiary: #F0f0f0; - --contrast: #414141; - --separator: #7777bb; - --shade: rgba(255,255,255,0.25); - --highlight: rgba(0,0,0,0.25); - --accent: rgb(250, 4, 197); -} - -@media (prefers-color-scheme: dark) { - :root { - --background: #222233; - --text: #ffffff; - --link: #8c8dff; - --secondary: #444455; - --tertiary: #333344; - --contrast: #C0C0C0; - --separator: #111122; - --shade: rgba(0,0,0,0.25); - --highlight: rgba(255,255,255,0.25); - --accent: rgb(250, 4, 197); - } -} +@import url('./posts.css'); +@import url('./constants.css'); +@import url('./content.css'); body { - background: var(--background); - color: var(--text); - font-size: 15px; - padding: 0; - margin: 0; - font-family: Arial, Helvetica, sans-serif; + background: var(--background); + color: var(--text); + font-size: 15px; + padding: 0; + margin: 0; + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; + /* position: relative; */ } * { - box-sizing: border-box; + box-sizing: border-box; } fieldset { - padding: 0; - margin: 0; - border: none; + padding: 0; + margin: 0; + border: none; } .toolbar { - position: fixed; - bottom: 0; - left: 0; - right: 0; - border-top: 1px solid var(--secondary); - font-size: 1.5rem; - background: var(--tertiary); + position: fixed; + bottom: 0; + left: 0; + right: 0; + border-top: 1px solid var(--secondary); + font-size: 1.5rem; + background: var(--tertiary); } .toolbar ul { - display: flex; - flex-direction: row; + display: flex; + flex-direction: row; } .toolbar ul li { - display: inline-block; - text-align: center; - flex-grow: 1; - position: relative; - padding: 0; - margin: 0; - border-right: 1px solid var(--secondary); + display: inline-block; + text-align: center; + flex-grow: 1; + position: relative; + padding: 0; + margin: 0; + border-right: 1px solid var(--secondary); } .badge { - position: absolute; - right: calc(50% - 1.35rem); - top: 0.25rem; - font-size: 0.8rem; - border-radius: 20px; - padding: 0.1rem 0.25rem; - background: var(--accent); + position: absolute; + right: calc(50% - 1.35rem); + top: 0.25rem; + font-size: 0.8rem; + border-radius: 20px; + padding: 0.1rem 0.25rem; + background: var(--accent); } .badge span { - display: none; + display: none; } .toolbar ul { - list-style-type: none; - padding: 0; - margin: 0; + list-style-type: none; + padding: 0; + margin: 0; } .toolbar ul li .label { - display: none; + display: none; } .toolbar ul li a { - display: block; - padding: 0.5rem 2rem 1rem; - color: var(--text); - text-decoration: none; - letter-spacing: 0.04rem; - + display: block; + padding: 0.5rem 2rem 1rem; + color: var(--text); + text-decoration: none; + letter-spacing: 0.04rem; } #main { - padding-bottom: 60px; + padding-bottom: 60px; } - nav ul { - list-style-type: none; - margin: 0; - padding: 0; + list-style-type: none; + margin: 0; + padding: 0; } - #nav { - /* display: none; */ - position: fixed; - bottom: 0; - left: 0; - right: 0; - - border-top: 1px solid var(--secondary); - font-size: 1.5rem; - background: var(--tertiary); + /* display: none; */ + position: fixed; + bottom: 0; + left: 0; + right: 0; + border-top: 1px solid var(--secondary); + font-size: 1.5rem; + background: white; } - #nav ul { - display: flex; - flex-direction: row; + display: flex; + flex-direction: row; } #nav ul li { - display: inline-block; - text-align: center; - flex-grow: 1; - position: relative; - padding: 0; - margin: 0; - border-right: 1px solid var(--secondary); + display: inline-block; + text-align: center; + flex-grow: 1; + position: relative; + padding: 0; + margin: 0; + border-right: 1px solid var(--secondary); } -#nav ul li a { - display: block; - text-decoration: none; - padding: 0.5rem 2rem 1rem; +#nav ul li a { + display: block; + text-decoration: none; + padding: 0.5rem 2rem 1rem; } -#nav ul li#logo { display: none; } +#nav ul li#logo { + display: none; +} #menu { - width: 90vw; - max-width: 300px; - position: fixed; - top: 0; - left: -100%; - bottom: 0; - transition: left 0.25s; - box-shadow: 10px 0px 5px rgba(0,0,0,0.25); - - overflow-y: auto; - background: var(--tertiary); - border-right: 1px solid var(--separator); - flex-grow: 0; - font-size: 14px; - letter-spacing: 0.04rem; - padding-bottom: 2rem; + width: 90vw; + max-width: 300px; + position: fixed; + top: 0; + left: -100%; + bottom: 0; + transition: left 0.25s; + box-shadow: 10px 0px 5px rgba(0, 0, 0, 0.25); + + overflow-y: auto; + background: var(--tertiary); + border-right: 1px solid #000000; + flex-grow: 0; + font-size: 14px; + letter-spacing: 0.04rem; + padding-bottom: 2rem; } #menu.active { - left: 0; + left: 0; } #menu form { - padding: 0.5rem 1rem; + padding: 0.5rem 1rem; } #menu input { - width: 100%; + width: 100%; } #menu a { - color: var(--text); - text-decoration: none; + color: var(--text); + text-decoration: none; - padding: 0.5rem 1rem; - display: block; - + padding: 0.5rem 1rem; + display: block; } #menu a:hover { - background: var(--highlight); -} - -#content { - padding-bottom: 3rem; -} - -#content.nonav { - padding-bottom: 0; + background: var(--highlight); } #top_nav { - margin-top: 1rem; - display: none; + margin-top: 1rem; + display: none; } #close_menu { - background: none; - border: 0; - padding: 1rem; - width: 100%; - text-align: right; + background: none; + border: 0; + padding: 1rem; + width: 100%; + text-align: right; } #top_feeds { - margin-top: 1rem; - font-size: 0.75rem; + margin-top: 1rem; + font-size: 0.75rem; } #top_nav li { - position: relative; + position: relative; } #menu li.current a { - background-color: var(--secondary); -} + background-color: navy; + color: #fff; +} #top_feeds li a { - display: flex; - align-items: center; + display: flex; + align-items: center; } #top_feeds li a img { - width: 25px; - height: 25px; - margin-right: 1rem; + width: 25px; + height: 25px; + margin-right: 1rem; } - @media screen and (min-width: 769px) { + #wrapper { + height: 100vh; + display: flex; + flex-direction: row; + } + + #close_menu { + display: none; + } - #wrapper { - height: 100vh; - display: flex; - flex-direction: row; - } - - #close_menu { - display: none; - } - - #nav { - width: 50px; - overflow-y: auto; - background: var(--secondary); - border-right: 1px solid var(--separator); - position: inherit; - flex-shrink: 0; - } - - - #nav ul li { - display: none; - } - #nav ul li a { - padding: 0; - } - #nav ul li#logo { display: block; text-align: center; padding-top: 1rem; } - - - #menu { - position: inherit; - box-shadow: none; - } - - - #top_nav { - display: block; - } - - - #top_feeds { - margin-top: 2rem; - font-size: 0.75rem; - } - - - #content { - flex-grow: 1; - flex-shrink: 1; - overflow-y: auto; - } - - #content .stream { - margin: 1rem; - } - - - .toolbar { - position: relative; - height: 100vh; - flex-shrink: 0; - border-right: 1px solid var(--secondary); - border-top: none; - font-size: 2rem; - background: var(--tertiary); - } - - .toolbar ul { - display: block; - } - - .toolbar ul li { - text-align: left; - display: block; - position: relative; - border-right: none; - border-bottom: 1px solid var(--secondary); - } - - - .badge { - position: absolute; - right: 0.25rem; - top: 0.25rem; - font-size: 0.8rem; - border-radius: 20px; - padding: 0.25rem 0.5rem; - background: var(--shade); - } - .badge span { - display: none; - } - - .toolbar ul li .label { - display: inline; - } - - .toolbar { - font-size: 0.9rem; - } - - .toolbar ul li a { - padding: 1rem 0.5rem; - padding-right: 2rem; - color: var(--text); - text-decoration: none; - letter-spacing: 0.04rem; - } + #nav { + width: 50px; + overflow-y: auto; + background: var(--secondary); + border-right: 1px solid var(--separator); + position: inherit; + flex-shrink: 0; + } + + #nav ul li { + display: none; + } + #nav ul li a { + padding: 0; + } + #nav ul li#logo { + display: block; + text-align: center; + padding-top: 1rem; + } + + #menu { + position: inherit; + box-shadow: none; + } + + #top_nav { + display: block; + } + + #top_feeds { + margin-top: 2rem; + font-size: 0.75rem; + } + + /* #content .stream { + margin: 1rem; + } */ + + .toolbar { + position: relative; + height: 100vh; + flex-shrink: 0; + border-right: 1px solid var(--secondary); + border-top: none; + font-size: 2rem; + background: var(--tertiary); + } + + .toolbar ul { + display: block; + } + + .toolbar ul li { + text-align: left; + display: block; + position: relative; + border-right: none; + border-bottom: 1px solid var(--secondary); + } + + .badge { + position: absolute; + right: 0.25rem; + top: 0.25rem; + font-size: 0.8rem; + border-radius: 20px; + padding: 0.25rem 0.5rem; + background: var(--shade); + } + .badge span { + display: none; + } + + .toolbar ul li .label { + display: inline; + } + + .toolbar { + font-size: 0.9rem; + } + + .toolbar ul li a { + padding: 1rem 0.5rem; + padding-right: 2rem; + color: var(--text); + text-decoration: none; + letter-spacing: 0.04rem; + } } .toolbar ul li a:hover { - background: var(--highlight); + background: var(--highlight); } #header { - width: 100%; - font-family: 'Courier New', Courier, monospace; - padding: 0.5rem; - background: var(--separator); - position: relative; + width: 100%; + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; + padding: 0.5rem; + background: var(--separator); + position: relative; } #header nav { - position: absolute; - right: 2rem; - top: 0.5rem; + position: absolute; + right: 2rem; + top: 0.5rem; } #main { - height: 100vh; - overflow-y: scroll; - flex-grow: 1; + height: 100vh; + overflow-y: scroll; + flex-grow: 1; } -a { color: var(--link); } +a { + color: var(--link); +} .stream { - width: 100%; - max-width: 100%; - text-overflow: ellipsis; - overflow-x: hidden; + width: 100%; + max-width: 100%; + text-overflow: ellipsis; + overflow-x: hidden; } @media screen and (min-width: 769px) { + .stream { + max-width: 40rem; + } - .stream { - max-width: 40rem; - } - - .box { - max-width: 40rem; - } - + .box { + max-width: 40rem; + } } header { - color: var(--text); - font-weight: bold; - padding: 0.5rem 1rem; - background: var(--separator); + color: #fff; + font-weight: bold; + padding: 0.5rem 1rem; + background: var(--separator); + font-size: large; } - header.back { - display: flex; - align-items: center; - gap: 1rem; +header.back { + display: flex; + align-items: center; + gap: 1rem; } - header .unread { - float: right; - font-size: 0.8rem; - border-radius: 5px; - padding: 0.25rem 0.5rem; - background: var(--highlight); - text-decoration: none; - color: var(--text); +header .unread { + float: right; + font-size: 0.8rem; + border-radius: 5px; + padding: 0.25rem 0.5rem; + background: var(--highlight); + text-decoration: none; + color: var(--text); } -header a { - text-decoration: none; +header a { + text-decoration: none; } .empty { - padding: 1rem; - color: var(--highlight); + padding: 1rem; + color: #000080; } - .activity { - border-bottom: 1px solid var(--secondary); - background: var(--tertiary); - padding: 1rem 1rem; - line-height: 1.25rem; + border-bottom: 1px solid var(--secondary); + background: var(--background); + padding: 1rem 1rem; + line-height: 1.25rem; } .byline { - display: flex; - flex-direction: row; - align-items: center; - gap: 1rem; + display: flex; + flex-direction: row; + align-items: center; + gap: 1rem; } .author { - font-weight: bold; - color: var(--text); - text-decoration: none; - display: block; + font-weight: bold; + color: var(--text); + text-decoration: none; + display: block; } .handle { - color: var(--contrast); + color: var(--contrast); } - .personCard { - display: flex; - flex-direction: row; - align-items: start; - gap: 1rem; + display: flex; + flex-direction: row; + align-items: start; + gap: 1rem; } .personCard .profile { - flex-grow: 1; + flex-grow: 1; } .personCard .author { - font-weight: bold; - color: var(--text); - text-decoration: none; - display: block; + font-weight: bold; + color: var(--text); + text-decoration: none; + display: block; } .personCard .handle { - color: var(--contrast); + color: var(--contrast); } .personCard .tools { - flex-shrink: 0; - flex-grow: 0; + flex-shrink: 0; + flex-grow: 0; } #lookup_results .personCard { - gap: 0; + gap: 0; } -.activity .content { - padding-left: calc(50px + 1rem); -} - -.content_warning { - background: var(--shade); - padding: 0.5rem 1rem; - display: flex; -} - -.content_warning .tools { - flex-grow: 1; - text-align: right; - /* padding-right: 1rem; */ -} - -.content_warning .tools a { - margin: 0px auto; - padding: 0.25rem 1rem; - border-radius: 4px; - background: var(--shade); - text-decoration: none; +.note-activity { + background-color: white; + border-radius: 4px; + padding: 20px; + margin-top: 15px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); } @media screen and (min-width: 769px) { - .activity .content { - padding-left: 0; - } - .activity .content_warning { - padding-left: 0.5rem; - } + .activity .content { + padding-left: 0; + } + .activity .content_warning { + padding-left: 0.5rem; + } } -.activity .collapsed{ - display: none; +.activity .collapsed { + display: none; } .activity .boost { - background: var(--shade); - padding: 0.25rem 0.5rem; - margin-bottom: 1rem; + /* background: var(--background); */ + /* padding: 0.1; */ + font-size: smaller; + margin-bottom: 0.25rem; } .avatar { - height: 50px; - width: 50px; + height: 50px; + width: 50px; } .activity footer { - display: flex; - flex-direction: row; - align-items: center; + display: flex; + flex-direction: row; + align-items: center; } .permalink { - color: var(--secondary); - text-decoration: none; + color: var(--secondary); + text-decoration: none; + margin-top: 2rem; } .permalink:hover { - color: var(--link); - text-decoration: underline; + color: var(--link); + text-decoration: underline; } .activity .attachment { - background: var(--shade); + background: var(--shade); } .activity .attachment img, .activity .attachment video { - - margin: 0px auto; - width: 100%; - height: 200px; - object-fit: contain; + margin: 0px auto; + width: 100%; + height: 200px; + object-fit: contain; } #composer { - padding: 1rem; + padding: 1rem; } @media screen and (min-width: 769px) { - #composer { - padding: 0; - margin-top: 1rem; - } + #composer { + padding: 0; + margin-top: 1rem; + } } #composer.mini { - margin-bottom: 0; - background-color: var(--tertiary); - border-bottom: 1px solid var(--secondary); - position: fixed; - bottom: 50px; - left: 0; - width: 100%; + margin-bottom: 0; + background-color: var(--tertiary); + border-bottom: 1px solid var(--secondary); + position: fixed; + bottom: 50px; + left: 0; + width: 100%; } #composer.mini fieldset { - display: flex; + display: flex; } - #composer.mini #post { - flex-grow: 1; + flex-grow: 1; } #composer.mini #submit { - border-radius: 0; + border-radius: 0; } - textarea#post { - width: 100%; - height: 5rem; - margin-bottom: 0.5rem; + width: 100%; + height: 5rem; + margin-bottom: 0.5rem; } -input#cw { - width: 100%; - margin-bottom: 0.5rem; +input#cw { + width: 100%; + margin-bottom: 0.5rem; } #submit { - padding: 0.5rem 1rem; - background: #0cc13f; - color: var(--text); - border: none; - border-radius: 5px; - float: right; - + padding: 0.5rem 1rem; + background: #0cc13f; + color: var(--text); + border: none; + border-radius: 5px; + float: right; } -.content .tools { flex-grow: 1; } -.content .tools div { display: inline-block; } -.content .tools button { font-size: 1rem; background: none; border: none; padding: 0; margin-right: 0.5rem; } -/* .content .tools button.active { background: var(--highlight); } */ -.content .tools button .active { display: none; } -.content .tools button.active .active { display: block; } -.content .tools button.active .inactive { display: none; } - -button.follow { background: none; border: none; } -button.follow .active { display: none; } -button.follow.active .active { display: block; } - -button.follow.active .inactive { display: none; } - -button.bigfollow { - background: #0cc13f; - color: var(--text); - border: none; - border-radius: 5px; - padding: 0.5rem 1rem; +button.follow { + background: none; + border: none; +} +button.follow .active { + display: none; +} +button.follow.active .active { + display: block; } -button.bigfollow .active { display: none; } -button.bigfollow.active .active { display: block; } -button.bigfollow.active .inactive { display: none; } +button.follow.active .inactive { + display: none; +} +button.bigfollow { + background: #0cc13f; + color: var(--text); + border: none; + border-radius: 5px; + padding: 0.5rem 1rem; +} +button.bigfollow .active { + display: none; +} +button.bigfollow.active .active { + display: block; +} +button.bigfollow.active .inactive { + display: none; +} @media screen and (min-width: 769px) { - .content .tools button { font-size: 1.5rem; } + .content .tools button { + font-size: 1.5rem; + } } .notification { - margin-bottom: 1rem; + margin-bottom: 1rem; } -.notification a { - color: var(--contrast); +.notification a { + color: var(--contrast); } .preview { - padding-left: 1rem; - color: var(--contrast); + padding-left: 1rem; + color: var(--contrast); } .Follow .preview { - display: flex; - flex-direction: row; - gap: 1rem; + display: flex; + flex-direction: row; + gap: 1rem; } .Follow .preview .avatar { - height: 50px; - width: 50px; + height: 50px; + width: 50px; } .showThread { - display: inline-block; - margin: 0px auto; - padding: 0.25rem 1rem; - border-radius: 4px; - background: var(--shade); - text-decoration: none; + display: inline-block; + margin: 0px auto; + padding: 0.25rem 1rem; + border-radius: 4px; + background: var(--shade); + text-decoration: none; } .moreLink { - display: inline-block; - margin: 1rem auto; - font-size: 1.25rem; - padding: 0.25rem 1rem; - border-radius: 4px; - background: var(--shade); - text-decoration: none; + display: inline-block; + margin: 1rem auto; + font-size: 1.25rem; + padding: 0.25rem 1rem; + border-radius: 4px; + background: var(--shade); + text-decoration: none; } .box { - margin: 1rem; - background: var(--tertiary); + margin: 1rem; + background: var(--tertiary); } .box a { - display: flex; - padding: 1rem; - text-decoration: none; + display: flex; + padding: 1rem; + text-decoration: none; } .box a span { - flex-grow: 1; - text-align: right; + flex-grow: 1; + text-align: right; } .box form { - padding: 1rem; + padding: 1rem; } .box fieldset { - margin-bottom: 1rem; + margin-bottom: 1rem; } .box fieldset p { - display: flex; + display: flex; } .box fieldset p label { - width: 100px; - flex-grow: 0; - flex-shrink: 0; + width: 100px; + flex-grow: 0; + flex-shrink: 0; } .box fieldset legend { - font-weight: bold; + font-weight: bold; } -#emojis input { - font-size: 2rem; +#emojis { + display: block; } +#emojis input { + font-size: 2rem; +} +#emojis .emoji-setting { + border-bottom: 2px solid #d3d3d3; +} .profileHeader { - height: 150px; - background: var(--separator); + height: 150px; + background: var(--separator); } .profileHeader img { - object-fit: cover; - height: 150px; - width: 100%; + object-fit: cover; + height: 150px; + width: 100%; } /* .profile { background: var(--tertiary); } */ - .profileToolbar { - padding: 1rem; - display: flex; + padding: 1rem; + display: flex; } .profileToolbar .avatarLink { - flex-grow: 0; - margin-top: calc(-50px - 1rem); + flex-grow: 0; + margin-top: calc(-50px - 1rem); } .profileToolbar .avatar { - width: 110px; - height: 110px; - border: 5px solid var(--tertiary); + width: 110px; + height: 110px; + border: 5px solid var(--tertiary); } .profileToolbar .tools { - text-align: right; - flex-grow: 1; + text-align: right; + flex-grow: 1; } - .profileBody { - padding: 0 1rem 1rem; + padding: 0 1rem 1rem; } .profileBody .author { - font-size: 1.25rem; - margin-bottom: 0.25rem; + font-size: 1.25rem; + margin-bottom: 0.25rem; } - .inbox { - display: flex; - flex-direction: column; - position: relative; - padding-bottom: 60px; - height: calc(100vh - 90px); + display: flex; + flex-direction: column; + position: relative; + padding-bottom: 60px; + height: calc(100vh - 90px); } @media screen and (min-width: 769px) { - .inbox { - padding-bottom: 0; - height: calc(100vh - 65px); - } + .inbox { + padding-bottom: 0; + height: calc(100vh - 65px); + } } .inbox .messages { - flex-grow: 1; - flex-direction: column-reverse; - display: flex; - overflow-y: auto; + flex-grow: 1; + flex-direction: column-reverse; + display: flex; + overflow-y: auto; } .inbox .message { - margin: 0.25rem 1rem; + margin: 0.25rem 1rem; } .message_text { - background: var(--highlight); - border-radius: 0.5rem; - padding: 1rem; - max-width: 75%; - display: inline-block; + background: white; + border-radius: 0.5rem; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); + padding: 1rem; + max-width: 75%; + display: inline-block; } .message_timestamp { - margin-top: 0.25rem; - font-size: 0.8rem; - color: var(--highlight); + margin-top: 0.25rem; + font-size: 0.8rem; + color: var(--highlight); } .inbox .message_text *:first-child { - margin-top: 0; + margin-top: 0; } .inbox .message_text *:last-child { - margin-bottom: 0; + margin-bottom: 0; } -.inbox .message.outgoing { - display: flex; - flex-direction: column; - align-items: flex-end; +.inbox .message.outgoing { + display: flex; + flex-direction: column; + align-items: flex-end; } -.inbox .message.outgoing .message_text { - background: var(--shade); +.inbox .message.outgoing .message_text { + background: var(--separator); + color: white; } .feeds { - flex-shrink: 1; - background: var(--tertiary); + flex-shrink: 1; + background: var(--tertiary); } .feeds.inbox_visible { - display: none; + display: none; } @media screen and (min-width: 769px) { - - #composer.mini { - background: none; - border-bottom: none; - bottom: 0; - left: 0; - position: inherit; - } + #composer.mini { + background: none; + border-bottom: none; + bottom: 0; + left: 0; + position: inherit; + } } .feeds .feed { - position: relative; - padding: 0.5rem 1rem; - padding-right: 4rem; - border-bottom: 1px solid var(--secondary); - display: flex; - align-items: center; + position: relative; + padding: 0.5rem 1rem; + padding-right: 1rem; + border-bottom: 1px solid var(--secondary); + display: flex; + align-items: center; } .feeds .feed .avatar { - width: 25px; - height: 25px; - margin-right: 1rem; + width: 25px; + height: 25px; + margin-right: 1rem; } -.feeds .feed a { - text-decoration: none; +.feeds .feed a { + text-decoration: none; } .feeds .unread { - font-weight: bold; - border-right: 10px solid var(--accent); - /* background: var(--secondary); */ + font-weight: bold; + border-right: 10px solid var(--accent); + /* background: var(--secondary); */ +} + +.current { + color: #fff; } .feeds .current { - /* font-weight: bold; */ - background: var(--secondary); + /* font-weight: bold; */ + background: var(--secondary); } .meta_tag { - background: var(--shade); - color: var(--contrast); - border-radius: 3px; - font-size: 0.7rem; - padding: 0.15rem; + background: var(--shade); + color: var(--contrast); + border-radius: 3px; + font-size: 0.7rem; + padding: 0.15rem; } details#bio { - margin-top: 1rem; -} \ No newline at end of file + margin-top: 1rem; +} + +.preferences-settings div { + display: flex; + align-items: center; + margin-bottom: 10px; +} + +.preferences-settings { + padding: 20px; + margin-bottom: 20px; + border-radius: 4px; + color: black; + background-color: white; + padding: 20px; + max-width: 40rem; + margin-top: 15px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); +} + +label { + width: 100px; + margin-right: 10px; +} + +input { + padding: 8px 15px; + margin: 8px 0; + max-width: 100%; + display: inline-block; + border: 1px solid #ccc; + border-radius: 4px; + box-sizing: border-box; +} + +input:focus { + outline: none; + border-color: #4caf50; + box-shadow: 0 0 5px rgba(76, 175, 80, 0.5); +} + +input::placeholder { + color: #a9a9a9; + font-style: italic; +} + +input:hover { + border-color: #888; +} +.preferences-form legend { + font-weight: bold; + color: #00018c; +} +.preferences-form button { + background-color: #3cb4c7; + color: #333344; + border: none; + padding: 10px 20px; + text-align: center; + text-decoration: none; + display: inline-block; + font-size: 16px; + margin: 4px 2px; + transition: background-color 0.3s; + cursor: pointer; + border-radius: 5px; +} + +.preferences-header { + color: black; +} + +.preferences-settings legend { + color: black; + font-size: small; + font-weight: bold; +} + +.preferences-form button:hover { + background-color: #e6b800; +} + +.preferences-form header { + background: -webkit-linear-gradient(left, #d3d3d3, #d3d3d3, #d3d3d3); + -webkit-background-clip: text; + width: 20ch; + white-space: nowrap; + overflow: hidden; + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; + font-size: 1.2em; +} +.preferences-form .form-group { + border-bottom: 2px solid #d3d3d3; +} +.queue-status header { + background: -webkit-linear-gradient(left, #d3d3d3, #d3d3d3, #d3d3d3); + -webkit-background-clip: text; + width: 20ch; + white-space: nowrap; + overflow: hidden; + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; + color: black; + font-size: 1.2em; +} +.queue-status .queue-details { + padding: 20px; + margin-bottom: 20px; + border-radius: 4px; + color: black; + background-color: white; + padding: 20px; + max-width: 40rem; + margin-top: 15px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); +} + +#composer_form { + background: white; + margin: 20px auto; + width: 80%; + max-width: 700px; + border: 1px solid #ddd; + padding: 20px; + border-radius: 8px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} + +#composer_form button { + background-color: #3cb4c7; + color: #333344; + border: none; + padding: 10px 20px; + text-align: center; + text-decoration: none; + display: inline-block; + font-size: 16px; + margin: 4px 2px; + transition: background-color 0.3s; + cursor: pointer; + border-radius: 5px; +} + +#composer_form button:hover { + background-color: #e6b800; +} + +.notification-activity { + background-color: white; + border-radius: 4px; + padding: 20px; + margin-top: 15px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); +} + +.form-group { + font-size: smaller; +} + +.emoji-setting { + font-size: smaller; +} + +.stream header a { + color: white; +} + +.outgoing .u-url { + color: white; +} + +.inReplyTo { + display: none; +} + +.to { + display: none; +} + +.mini-cw { + display: none; +} + +.authetication-form { + /* min-width: 250px; */ + max-width: 400px; + margin: 150px auto; + padding: 20px; + border: 5px solid var(--authentication-color); + background-color: var(--background); + border-radius: 20px; +} + +.authetication-form .form-label { + display: block; + margin-bottom: 5px; + font-weight: bold; +} + +.authetication-form .form-input { + width: 100%; + padding: 10px; + border: 2px solid var(--authentication-color); + border-radius: 5px; + box-sizing: border-box; + font-size: 14px; +} + +.authetication-form .form-input:focus { + outline: none; + border-color: #3b99fc; + box-shadow: 0 0 5px rgba(59, 153, 252, 0.5); +} + +.authetication-form .form-button { + display: block; + width: 100%; + padding: 10px; + background-color: var(--authentication-color); + color: white; + border: none; + border-radius: 20px; + font-size: 16px; + cursor: pointer; + margin-top: 10px; + font-family: Verdana, sans-serif; +} + +.authetication-form .form-title { + font-family: Verdana, sans-serif; + font-size: 24px; + font-weight: 900; + text-align: center; + color: var(--authentication-color); + margin: 0px 0px 10px 0px; +} +@media (max-width: 600px) { + h1.form-title { + font-size: 18px; + } +} + +.authentication-body { + background-image: url('https://i.postimg.cc/wjC2dDw0/1-1-2.jpg'); + background-size: cover; + background-repeat: no-repeat; + background-position: center center; +} diff --git a/routes/account.js b/routes/account.js index 695d8536..84d70e51 100644 --- a/routes/account.js +++ b/routes/account.js @@ -1,41 +1,112 @@ import express from 'express'; import { getFollowers } from '../lib/account.js'; + +/** + * Express.js router for handling user profile-related routes. + * + * @typedef {Object} UserProfileRouter + * @property {Function} getProfile - Route handler for retrieving a user profile by name. + * @property {Function} getFollowers - Route handler for retrieving followers of a user profile by name. + * + * @example + * // Example usage: + * const userProfileRouter = express.Router(); + * userProfileRouter.get('/:name', userProfileHandlers.getProfile); + * userProfileRouter.get('/:name/followers', userProfileHandlers.getFollowers); + * app.use('/profiles', userProfileRouter); + */ export const router = express.Router(); -router.get('/:name', function (req, res) { +/** + * Handle GET requests for a user profile by name. + * + * @function + * @param {Object} req - Express.js request object. + * @param {Object} res - Express.js response object. + * @returns {void} Responds with a user profile or redirects based on the request. + * + * @throws {Error} Responds with a 400 Bad Request if the 'name' parameter is missing. + * @throws {Error} Responds with a 404 Not Found if no record is found for the provided 'name'. + * + * @example + * // Example route: + * // GET /profiles/:name + * router.get('/:name', function (req, res) { + * // ... (route handler implementation) + * }); + */ +router.get('/:name', (req, res) => { + // Extract the 'name' parameter from the request let name = req.params.name; + + // Handle missing 'name' parameter with a 400 Bad Request response if (!name) { return res.status(400).send('Bad request.'); } else { + // Obtain the domain from the app settings const domain = req.app.get('domain'); - // const username = name; + + // Append the user profile URL path to the domain name = `https://${domain}/u/${name}`; + // Check if the provided 'name' matches the stored user profile ID if (name !== req.app.get('account').actor.id) { + // Respond with a 404 Not Found if no record is found for the provided 'name' return res.status(404).send(`No record found for ${name}.`); } else { + // Check the 'Accept' header for JSON-LD format and respond accordingly if (req.headers.accept?.includes('application/ld+json')) { + // Respond with the user profile in JSON-LD format res.json(req.app.get('account').actor); } else { + // Redirect to the user profile URL or the default domain res.redirect(req.app.get('account').actor.url || `https://${domain}/`); } } } }); -router.get('/:name/followers', function (req, res) { +/** + * Handle GET requests for the followers of a user profile by name. + * + * @function + * @param {Object} req - Express.js request object. + * @param {Object} res - Express.js response object. + * @returns {void} Responds with a collection of followers or an error message based on the request. + * + * @throws {Error} Responds with a 400 Bad Request if the 'name' parameter is missing. + * @throws {Error} Responds with a 404 Not Found if no record is found for the provided 'name'. + * + * @example + * // Example route: + * // GET /profiles/:name/followers + * router.get('/:name/followers', function (req, res) { + * // ... (route handler implementation) + * }); + */ +router.get('/:name/followers', (req, res) => { + // Extract the 'name' parameter from the request let name = req.params.name; + + // Handle missing 'name' parameter with a 400 Bad Request response if (!name) { return res.status(400).send('Bad request.'); } else { + // Obtain the domain from the app settings const domain = req.app.get('domain'); + // Append the user profile URL path to the domain name = `https://${domain}/u/${name}`; + // Check if the provided 'name' matches the stored user profile ID if (name !== req.app.get('account').actor.id) { + // Respond with a 404 Not Found if no record is found for the provided 'name' return res.status(404).send(`No record found for ${name}.`); } else { + // Retrieve followers for the user profile const followers = getFollowers(); + + // Assemble the followers collection in ActivityStreams format const followersCollection = { type: 'OrderedCollection', totalItems: followers.length, @@ -49,6 +120,7 @@ router.get('/:name/followers', function (req, res) { }, '@context': ['https://www.w3.org/ns/activitystreams'] }; + // Respond with the followers collection in JSON format res.json(followersCollection); } } diff --git a/routes/accountHandler.js b/routes/accountHandler.js new file mode 100644 index 00000000..dc8b21d3 --- /dev/null +++ b/routes/accountHandler.js @@ -0,0 +1,55 @@ +import express from 'express'; +import { authenticateLogin, writeEnvToFile, createAccount } from '../lib/authentication.js'; +import { getAccount, ifAccount } from '../lib/account.js'; + +export const router = express.Router(); + +/* The code `router.get('/create', async (req, res) => { ... })` is defining a route handler for a GET +request to the '/create' endpoint. */ +router.get('/create', async (req, res) => { + res.status(200).render('createAccount', { + layout: 'authentication' + }); +}); + +/* The code `router.post('/create', (req, res) => { ... })` is defining a route handler for a POST +request to the '/create' endpoint. */ +router.post('/create', async (req, res) => { + await writeEnvToFile(req, res); + await createAccount(req, res); +}); + +/* The code `router.get('/login', (req, res) => { ... })` is defining a route handler for a GET request +to the '/login' endpoint. */ +router.get('/login', (req, res) => { + if (!ifAccount()) { + res.redirect('/account/create'); + } + res.status(200).render('login', { + layout: 'authentication' + }); +}); + +/* The code `router.post('/login', (req, res) => { ... })` is defining a route handler for a POST +request to the '/login' endpoint. */ +router.post('/login', (req, res) => { + const { username, password } = req.body; + + if (authenticateLogin(username, password)) { + const myaccount = getAccount(); + res.cookie('token', myaccount.apikey); + res.redirect('/private'); + } else { + res.status(200).render('login', { + layout: 'authentication', + message: "Username or password don't match" + }); + } +}); + +/* The code router.get('/logout', (req, res) => { ... }) is defining a route handler for a GET +request to the '/logout' endpoint. */ +router.get('/logout', (req, res) => { + res.clearCookie('token'); + res.redirect('/account/login'); +}); diff --git a/routes/admin.js b/routes/admin.js index b1f3e718..a3a16332 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -17,15 +17,20 @@ import { isFollowing, getInboxIndex, getInbox, - writeInboxIndex + writeInboxIndex, + updateAccount } from '../lib/account.js'; import { fetchUser } from '../lib/users.js'; import { getPrefs, INDEX, searchKnownUsers, updatePrefs } from '../lib/storage.js'; import { ActivityPub } from '../lib/ActivityPub.js'; import { queue } from '../lib/queue.js'; +const { DOMAIN } = process.env; export const router = express.Router(); const logger = debug('ono:admin'); +/** + * Return the INDEX in form of JSON + */ router.get('/index', async (req, res) => { res.json(INDEX); }); @@ -38,6 +43,10 @@ router.get('/index', async (req, res) => { | |__| / ____ \ ____) | | | | |_) | |__| / ____ \| | \ \| |__| | |_____/_/ \_\_____/|_| |_|____/ \____/_/ \_\_| \_\_____/ + */ +/** + * Render the dashboard console in the html + * display the feeds */ router.get('/', async (req, res) => { const offset = parseInt(req.query.offset) || 0; @@ -75,6 +84,10 @@ router.get('/', async (req, res) => { |_| \_|\____/ |_| |_____|_| |_____\_____/_/ \_\_| |_____\____/|_| \_|_____/ */ + +/** + * Render the notifications by fetching the notification API + */ router.get('/notifications', async (req, res) => { const likes = await getLikes(); const offset = parseInt(req.query.offset) || 0; @@ -87,7 +100,6 @@ router.get('/notifications', async (req, res) => { notes.map(async notification => { const { actor } = await fetchUser(notification.notification.actor); let note, original; - // TODO: check if user is in following list actor.isFollowing = isFollowing(actor.id); if (notification.notification.type === 'Like' || notification.notification.type === 'Announce') { @@ -141,6 +153,9 @@ router.get('/notifications', async (req, res) => { }); }); +/** + * Load the feeds in the activity stream + */ router.get('/feeds/:handle?', async (req, res) => { const offset = parseInt(req.query.offset) || 0; const pageSize = 20; @@ -218,6 +233,9 @@ router.get('/feeds/:handle?', async (req, res) => { }); }); +/** + * Load the inboxes + */ router.get('/dms/:handle?', async (req, res) => { const inboxIndex = getInboxIndex(); let error, inbox, recipient, lastIncoming; @@ -284,6 +302,9 @@ router.get('/dms/:handle?', async (req, res) => { }); }); +/** + * Load the post using the GET method + */ router.get('/post', async (req, res) => { const to = req.query.to; const inReplyTo = req.query.inReplyTo; @@ -299,7 +320,6 @@ router.get('/post', async (req, res) => { if (req.query.edit) { console.log('COMPOSING EDIT', req.query.edit); prev = await getNote(req.query.edit); - // console.log("ORIGINAL", original); } res.status(200).render('partials/composer', { @@ -315,9 +335,20 @@ router.get('/post', async (req, res) => { }); }); +/** + * Update and create the post using the POST method + */ router.post('/post', async (req, res) => { - // TODO: this is probably supposed to be a post to /api/outbox - const post = await createNote(req.body.post, req.body.cw, req.body.inReplyTo, req.body.to, req.body.editOf); + const post = await createNote( + req.body.post, + req.body.cw, + req.body.inReplyTo, + req.body.to, + req.body.editOf, + req.body.canReply, + req.body.canBoost, + req.body.canFave + ); if (post.directMessage === true) { // return html partial of the new post for insertion in the feed res.status(200).render('partials/dm', { @@ -336,6 +367,9 @@ router.post('/post', async (req, res) => { } }); +/** + * Poll the new notifications, inboxes, activities. + */ router.get('/poll', async (req, res) => { const sincePosts = new Date(req.cookies.latestPost).getTime(); const sinceNotifications = parseInt(req.cookies.latestNotification); @@ -354,6 +388,9 @@ router.get('/poll', async (req, res) => { }); }); +/** + * Render the followers in the page + */ router.get('/followers', async (req, res) => { let following = await Promise.all( getFollowing().map(async f => { @@ -398,6 +435,9 @@ router.get('/followers', async (req, res) => { } }); +/** + * Render the following in the page + */ router.get('/following', async (req, res) => { let following = await Promise.all( getFollowing().map(async f => { @@ -449,6 +489,9 @@ router.get('/following', async (req, res) => { | | | | \ \| |____| | ____) | |_| |_| \_\______|_| |_____/ + */ +/** + * Render the preferewnce page with the preference using GET */ router.get('/prefs', (req, res) => { const following = getFollowing(); @@ -469,6 +512,9 @@ router.get('/prefs', (req, res) => { }); }); +/** + * Update the preference using POST + */ router.post('/prefs', (req, res) => { // lget current prefs. const prefs = getPrefs(); @@ -489,6 +535,24 @@ router.post('/prefs', (req, res) => { updatePrefs(prefs); }); +/** + * Update the username preference using POST + */ +router.post('/prefsAccount', (req, res) => { + // lget current prefs. + const updates = req.body; + const bio = updates.bio; + const img = updates.avatarInput; + console.log('GOT ACCOUNT UPDATES', updates); + updateAccount(updates.username, DOMAIN, bio, img).then(myaccount => { + // set the server to use the main account as its primary actor + ActivityPub.account = myaccount; + // app.set('account', myaccount); + }); + + res.redirect('/private'); +}); + const getFeedList = async (offset = 0, num = 20) => { const following = await getFollowing(); @@ -528,6 +592,9 @@ const getFeedList = async (offset = 0, num = 20) => { return feeds.slice(offset, offset + num); }; +/** + * Find the user given the user information and display the result + */ router.get('/find', async (req, res) => { let results = []; @@ -559,6 +626,9 @@ router.get('/find', async (req, res) => { }); }); +/** + * Render more feeds based on different indexes + */ router.get('/morefeeds', async (req, res) => { const feeds = await getFeedList(20, 100); @@ -569,6 +639,9 @@ router.get('/morefeeds', async (req, res) => { }); }); +/** + * Look up the user based on the user information + */ router.get('/lookup', async (req, res) => { const { actor } = await fetchUser(req.query.handle); if (actor) { @@ -582,6 +655,9 @@ router.get('/lookup', async (req, res) => { } }); +/** + * Follow a user given the user information using POST + */ router.post('/follow', async (req, res) => { const handle = req.body.handle; if (handle) { @@ -604,8 +680,6 @@ router.post('/follow', async (req, res) => { // send unfollow await ActivityPub.sendUndoFollow(actor, status.id); - // todo: this should just be a function like removeFollowing - let following = getFollowing(); // filter out the one we are removing @@ -622,6 +696,9 @@ router.post('/follow', async (req, res) => { res.status(404).send('not found'); }); +/** + * Like the post given the activity ID using POST + */ router.post('/like', async (req, res) => { const activityId = req.body.post; let likes = getLikes(); diff --git a/routes/inbox.js b/routes/inbox.js index 6041d173..6143d9da 100644 --- a/routes/inbox.js +++ b/routes/inbox.js @@ -17,10 +17,47 @@ import { import { createActivity, recordLike, recordUndoLike, recordBoost, getActivity } from '../lib/notes.js'; import debug from 'debug'; import { isIndexed } from '../lib/storage.js'; -export const router = express.Router(); const logger = debug('ono:inbox'); +/** + * Express.js router for handling incoming ActivityPub requests. + * + * @typedef {Object} ActivityPubRouter + * @property {Function} processActivity - Route handler for processing incoming ActivityPub requests. + * + * @example + * // Example usage: + * import { router as activityPubRouter } from './activityPubRouter'; + * app.use('/activitypub', activityPubRouter); + */ +export const router = express.Router(); + +/** + * Route handler for processing incoming ActivityPub requests. + * + * @function + * @async + * @param {Object} req - Express.js request object. + * @param {Object} res - Express.js response object. + * @returns {Promise} Resolves with a success response or rejects with an error response. + * + * @throws {Error} Responds with a 403 Forbidden if the actor is blocked. + * @throws {Error} Responds with a 403 Forbidden if the signature validation fails. + * + * @example + * // Example route: + * // POST /activitypub + * activityPubRouter.post('/', activityPubHandlers.processActivity); + */ router.post('/', async (req, res) => { + /** + * The incoming ActivityPub request payload. + * + * @type {Object} + * @property {string} type - The type of the incoming request (e.g., 'Create', 'Follow', 'Like'). + * @property {Object} actor - The actor associated with the request. + * @property {Object} object - The object of the request, containing the main content. + */ const incomingRequest = req.body; if (incomingRequest) { @@ -30,6 +67,13 @@ router.post('/', async (req, res) => { logger('New message', JSON.stringify(incomingRequest, null, 2)); logger('Looking up actor', incomingRequest.actor); + + /** + * The user object obtained from fetching the actor of the incoming request. + * + * @type {Object} + * @property {Object} actor - The actor object representing the user. + */ const { actor } = await fetchUser(incomingRequest.actor); // FIRST, validate the actor @@ -43,7 +87,6 @@ router.post('/', async (req, res) => { logger('Incoming follow request'); addFollower(incomingRequest); - // TODO: should wait to confirm follow acceptance? ActivityPub.sendAccept(actor, incomingRequest); break; case 'Undo': @@ -95,7 +138,7 @@ router.post('/', async (req, res) => { // log the boost itself to the activity stream try { - await createActivity(incomingRequest); + createActivity(incomingRequest); } catch (err) { console.error('Could not fetch boosted post...'); } @@ -114,9 +157,8 @@ router.post('/', async (req, res) => { if (incomingRequest.object.directMessage === true || addressedOnlyToMe(incomingRequest)) { await acceptDM(incomingRequest.object, incomingRequest.object.attributedTo); } else if (isReplyToMyPost(incomingRequest.object)) { - // TODO: What about replies to replies? should we traverse up a bit? if (!isIndexed(incomingRequest.object.id)) { - await createActivity(incomingRequest.object); + createActivity(incomingRequest.object); addNotification({ type: 'Reply', actor: incomingRequest.object.attributedTo, @@ -127,7 +169,7 @@ router.post('/', async (req, res) => { } } else if (isMention(incomingRequest.object)) { if (!isIndexed(incomingRequest.object.id)) { - await createActivity(incomingRequest.object); + createActivity(incomingRequest.object); addNotification({ type: 'Mention', actor: incomingRequest.object.attributedTo, @@ -138,21 +180,18 @@ router.post('/', async (req, res) => { } } else if (!incomingRequest.object.inReplyTo) { // this is a NEW post - most likely from a follower - await createActivity(incomingRequest.object); + createActivity(incomingRequest.object); } else { // this is a reply // from a following // or from someone else who replied to a following? // the visibility should be determined on the feed - // TODO: we may want to discard things NOT from followings - // since they may never be seen - // and we can always go fetch them... - await createActivity(incomingRequest.object); + createActivity(incomingRequest.object); } break; case 'Update': - await createActivity(incomingRequest.object); + createActivity(incomingRequest.object); break; default: logger('Unknown request type:', incomingRequest.type); diff --git a/routes/index.js b/routes/index.js index 08a7cf8f..12607b56 100644 --- a/routes/index.js +++ b/routes/index.js @@ -1,7 +1,8 @@ -export { router as account } from './account.js'; -export { router as webfinger } from './webfinger.js'; +export { router as UserProfileRouter } from './account.js'; +export { router as WebfingerRouter } from './webfinger.js'; export { router as inbox } from './inbox.js'; export { router as outbox } from './outbox.js'; export { router as admin } from './admin.js'; export { router as notes } from './notes.js'; export { router as publicFacing } from './public.js'; +export { router as accountHandler } from './accountHandler.js'; diff --git a/routes/notes.js b/routes/notes.js index 5095a96f..46040d78 100644 --- a/routes/notes.js +++ b/routes/notes.js @@ -6,6 +6,10 @@ dotenv.config(); const { DOMAIN } = process.env; +/** + * fetch the notes based on valid guid parameters + * either return the json response or to the url + */ router.get('/:guid', async (req, res) => { const guid = req.params.guid; if (!guid) { diff --git a/routes/outbox.js b/routes/outbox.js index e35bc4b9..28bf0047 100644 --- a/routes/outbox.js +++ b/routes/outbox.js @@ -2,17 +2,73 @@ import express from 'express'; import dotenv from 'dotenv'; import { getOutboxPosts } from '../lib/account.js'; -export const router = express.Router(); + dotenv.config(); +/** + * Express.js router for handling requests related to the user's outbox. + * + * @typedef {Object} OutboxRouter + * @property {Function} getOutbox - Route handler for retrieving the user's outbox posts. + * + * @example + * // Example usage: + * import { router as outboxRouter } from './outboxRouter'; + * app.use('/outbox', outboxRouter); + */ +export const router = express.Router(); + // const { // DOMAIN // } = process.env; +/** + * Route handler for retrieving the user's outbox posts. + * + * @function + * @async + * @param {Object} req - Express.js request object. + * @param {Object} res - Express.js response object. + * @returns {Promise} Resolves with the user's outbox collection or rejects with an error response. + * + * @throws {Error} Responds with a 400 Bad Request if the 'offset' query parameter is not a valid number. + * + * @example + * // Example route: + * // GET /outbox + * outboxRouter.get('/', outboxHandlers.getOutbox); + */ router.get('/', async (req, res) => { + /** + * The result object containing the total number of posts and an array of outbox posts. + * + * @type {Object} + * @property {number} total - The total number of outbox posts. + * @property {Array} posts - An array of outbox posts. + */ const { total, posts } = await getOutboxPosts(req.query.offset || 0); + + /** + * The URL of the user's outbox. + * + * @type {string} + */ const outboxUrl = req.app.get('account').actor.outbox; + /** + * The representation of the outbox collection to be sent in the response. + * + * @type {Object} + * @property {string} type - The type of the collection ('OrderedCollection' or 'OrderedCollectionPage'). + * @property {number} totalItems - The total number of items in the collection. + * @property {string} id - The unique identifier for the collection. + * @property {string} [first] - The URL of the first page of the collection. + * @property {string} [partOf] - The URL of the main collection that this page is part of. + * @property {string} [next] - The URL of the next page of the collection. + * @property {string} [prev] - The URL of the previous page of the collection. + * @property {Array} [orderedItems] - An array of ordered items in the collection. + * @property {Array} ['@context'] - The context of the collection. + */ const collection = { type: 'OrderedCollection', totalItems: total, @@ -20,20 +76,23 @@ router.get('/', async (req, res) => { '@context': ['https://www.w3.org/ns/activitystreams'] }; + // Check if the 'offset' query parameter is a valid number if (isNaN(req.query.offset)) { collection.first = `${outboxUrl}?offset=0`; } else { + // Adjust collection properties for paginated results const offset = parseInt(req.query.offset); collection.type = 'OrderedCollectionPage'; collection.id = `${outboxUrl}?offset=${offset}`; collection.partOf = outboxUrl; collection.next = `${outboxUrl}?offset=${offset + 10}`; - // todo: stop at 0 if (offset - 10 > 0) { collection.prev = `${outboxUrl}?offset=${offset - 10}`; } else { collection.first = `${outboxUrl}?offset=0`; } + + // Transform each post into an ordered item in the collection collection.orderedItems = posts; collection.orderedItems = collection.orderedItems.map(activity => { return { @@ -48,5 +107,6 @@ router.get('/', async (req, res) => { }); } + // Send the outbox collection in the response res.json(collection); }); diff --git a/routes/public.js b/routes/public.js index 556c509d..f3187ebc 100644 --- a/routes/public.js +++ b/routes/public.js @@ -3,12 +3,7 @@ import debug from 'debug'; import RSS from 'rss-generator'; import dotenv from 'dotenv'; -import { - getNote, - isMyPost, - // getAccount, - getOutboxPosts -} from '../lib/account.js'; +import { getNote, isMyPost, getAccount, getOutboxPosts, ifAccount } from '../lib/account.js'; import { getActivity, getLikesForNote, getReplyCountForNote } from '../lib/notes.js'; import { INDEX } from '../lib/storage.js'; import { ActivityPub } from '../lib/ActivityPub.js'; @@ -17,10 +12,14 @@ import { fetchUser } from '../lib/users.js'; export const router = express.Router(); dotenv.config(); -const { USERNAME, DOMAIN } = process.env; +const { USER_NAME, DOMAIN } = process.env; const logger = debug('notes'); +/** + * publish the post to go up the stream + * check all the posts below and above the threads + */ const unrollThread = async (noteId, results = [], ascend = true, descend = true) => { let post, actor; let stats; @@ -86,26 +85,20 @@ const unrollThread = async (noteId, results = [], ascend = true, descend = true) return results; }; +/** + * Renders the home page with the outbox posts fetched through the api + */ router.get('/', async (req, res) => { + if (!ifAccount()) { + console.log('No account found. Redirecting to account creation.'); + res.redirect('/private'); + } const offset = parseInt(req.query.offset) || 0; - const { - // total, - posts - } = await getOutboxPosts(offset); + const { posts } = await getOutboxPosts(offset); + + const myaccount = getAccount(); + ActivityPub.account = myaccount; const actor = ActivityPub.actor; - // const enrichedPosts = posts.map((post) => { - // let stats; - // if (isMyPost(post)) { - // const likes = getLikesForNote(post.id) - // stats = { - // likes: likes.likes.length, - // boosts: likes.boosts.length, - // replies: getReplyCountForNote(post.id), - // } - // post.stats = stats; - // } - // return post; - // }) res.render('public/home', { me: ActivityPub.actor, @@ -114,10 +107,13 @@ router.get('/', async (req, res) => { layout: 'public', next: offset + posts.length, domain: DOMAIN, - user: USERNAME + user: USER_NAME }); }); +/** + * Fetch the feed for the user and display it in the html + */ router.get('/feed', async (req, res) => { const { // total, @@ -125,7 +121,7 @@ router.get('/feed', async (req, res) => { } = await getOutboxPosts(0); const feed = new RSS({ - title: `${USERNAME}@${DOMAIN}`, + title: `${USER_NAME}@${DOMAIN}`, site_url: DOMAIN, pubDate: posts[0].published }); @@ -177,7 +173,7 @@ router.get('/notes/:guid', async (req, res) => { activitystream: notes, layout: 'public', domain: DOMAIN, - user: USERNAME + user: USER_NAME }); } } diff --git a/routes/webfinger.js b/routes/webfinger.js index 201b8fa3..8741d740 100644 --- a/routes/webfinger.js +++ b/routes/webfinger.js @@ -1,8 +1,35 @@ import express from 'express'; + +/** + * Express.js router for handling webfinger-related routes. + * + * @typedef {Object} WebfingerRouter + * @property {Function} getResource - Route handler for retrieving a webfinger resource. + * + * @example + * // Example usage: + * import { router as webfingerRouter } from './webfingerRouter'; + * app.use('/webfinger', webfingerRouter); + */ export const router = express.Router(); +/** + * Route handler for retrieving a webfinger resource. + * + * @function + * @param {Object} req - Express.js request object. + * @param {Object} res - Express.js response object. + * @returns {void} Responds with a webfinger resource or an error message based on the request. + * + * @throws {Error} Responds with a 400 Bad Request if the 'resource' query parameter is missing or incorrectly formatted. + * @throws {Error} Responds with a 404 Not Found if no record is found for the provided 'resource'. + * + */ router.get('/', function (req, res) { + // Extract the 'resource' query parameter from the request const resource = req.query.resource; + + // Check if the 'resource' parameter is missing or incorrectly formatted if (!resource || !resource.includes('acct:')) { return res .status(400) @@ -10,9 +37,12 @@ router.get('/', function (req, res) { 'Bad request. Please make sure "acct:USER@DOMAIN" is what you are sending as the "resource" query parameter.' ); } else { + // Check if the provided 'resource' matches the stored webfinger subject if (resource === req.app.get('account').webfinger.subject) { + // Respond with the webfinger resource in JSON format res.json(req.app.get('account').webfinger); } else { + // Respond with a 404 Not Found if no record is found for the provided 'resource' return res.status(404).send(`No record found for ${resource}.`); } }