diff --git a/.commitlintrc.js b/.commitlintrc.js
new file mode 100755
index 0000000..df53c3d
--- /dev/null
+++ b/.commitlintrc.js
@@ -0,0 +1,3 @@
+export default {
+ extends: ['@commitlint/config-conventional'],
+}
diff --git a/.editorconfig b/.editorconfig
new file mode 100755
index 0000000..43b07b3
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,15 @@
+# EditorConfig helps developers define and maintain consistent
+# coding styles between different editors and IDEs
+# editorconfig.org
+
+root = true
+
+[*]
+
+indent_style = space
+indent_size = 4
+
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
diff --git a/.eslintrc.js b/.eslintrc.js
deleted file mode 100644
index 3e22563..0000000
--- a/.eslintrc.js
+++ /dev/null
@@ -1,18 +0,0 @@
-module.exports = {
- env: {
- es2021: true,
- node: true
- },
- extends: 'eslint:recommended',
- overrides: [],
- parserOptions: {
- ecmaVersion: 'latest',
- sourceType: 'module'
- },
- rules: {
- indent: ['error', 'tab'],
- 'linebreak-style': ['error', 'windows'],
- quotes: ['error', 'single'],
- semi: ['error', 'always']
- }
-};
diff --git a/.gitattributes b/.gitattributes
new file mode 100755
index 0000000..cfdc41a
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,3 @@
+*.pbxproj -text
+# specific for windows script files
+*.bat text eol=lf
\ No newline at end of file
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
deleted file mode 100644
index d8a24b7..0000000
--- a/.github/workflows/build.yml
+++ /dev/null
@@ -1,64 +0,0 @@
-name: Build and Publish Docker Image
-
-on:
- push:
- branches: [main]
- workflow_dispatch:
-
-env:
- REGISTRY: ghcr.io
- IMAGE_NAME: ${{ github.repository }}
- IMAGE_TAG: ${{ github.sha }}
-
-jobs:
- build:
- runs-on: ubuntu-latest
- permissions:
- contents: read
- packages: write
-
- steps:
- - name: Checkout Dockerfile
- id: checkout
- uses: actions/checkout@v4
-
- - name: Setup QEMU
- id: qemu
- uses: docker/setup-qemu-action@v3
- with:
- image: tonistiigi/binfmt:latest
- platforms: all
-
- - name: Setup Docker Buildx
- id: buildx
- uses: docker/setup-buildx-action@v3
-
- - name: Login to GitHub Container Registry
- id: ghcr
- uses: docker/login-action@v3
- with:
- registry: ${{ env.REGISTRY }}
- username: ${{ github.repository_owner }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Extract metadata (tags, labels) for Docker
- id: meta
- uses: docker/metadata-action@v5
- with:
- images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- flavor: |
- latest=${{ startsWith(github.ref, 'refs/heads/main') }}
- suffix=-${{ github.sha }}
-
- - name: Build and push main Docker image
- id: build
- uses: docker/build-push-action@v5
- with:
- context: .
- file: ./Dockerfile
- platforms: linux/amd64,linux/arm64/v8
- cache-to: type=gha,mode=max,ignore-error=true
- cache-from: type=gha
- push: true
- tags: ${{ steps.meta.outputs.tags }}
- labels: ${{ steps.meta.outputs.labels }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..02591f6
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,78 @@
+name: Release
+
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - main
+ - dev
+
+jobs:
+ release:
+ name: Release
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ packages: write
+ timeout-minutes: 10
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ # Make sure the release step uses its own credentials:
+ # https://github.com/cycjimmy/semantic-release-action#private-packages
+ persist-credentials: false
+ fetch-depth: 0
+
+ - name: Cache dependencies
+ uses: actions/cache@v4
+ with:
+ path: '**/node_modules'
+ key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lockb') }}
+ restore-keys: ${{ runner.os }}-bun-
+
+ - name: Setup Bun
+ uses: oven-sh/setup-bun@v2
+
+ - name: Install dependencies
+ run: bun install --frozen-lockfile
+
+ - name: Build packages
+ run: bun run build:packages
+
+ - name: Setup QEMU
+ uses: docker/setup-qemu-action@v3
+ with:
+ platforms: amd64, arm64
+
+ - name: Setup Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Build and release
+ env:
+ RELEASE_WORKFLOW_STEP: release
+ GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}
+ DOCKER_REGISTRY_USER: ${{ github.repository_owner }}
+ DOCKER_REGISTRY_PASSWORD: ${{ secrets.REPOSITORY_PUSH_ACCESS }}
+ DEBUG: semantic-release:*
+ run: bunx multi-semantic-release --debug
+
+ # We call multi-semantic-release twice to publish in a different step
+ # An environment variable determines which plugins in the config to run
+ - name: Trigger Portainer webhooks
+ if: github.ref == 'refs/heads/main'
+ env:
+ RELEASE_WORKFLOW_STEP: publish
+ GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}
+ WEBSOCKET_API_PORTAINER_WEBHOOK_URL: ${{ secrets.WEBSOCKET_API_PORTAINER_WEBHOOK_URL }}
+ DISCORD_BOT_PORTAINER_WEBHOOK_URL: ${{ secrets.DISCORD_BOT_PORTAINER_WEBHOOK_URL }}
+ run: bunx multi-semantic-release
+
+ - name: Purge outdated images
+ uses: snok/container-retention-policy@v3.0.0
+ with:
+ account: ${{ github.repository_owner }}
+ token: ${{ secrets.DELETE_PACKAGES_TOKEN }}
+ image-names: "revanced-bot-*"
+ keep-n-most-recent: 5
+ cut-off: 3M
diff --git a/.gitignore b/.gitignore
old mode 100644
new mode 100755
index 4fa1d7b..a1a690b
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,60 @@
-node_modules
-model
-test.js
-eng.traineddata
-bots/*
-server/**/**
-test/*
\ No newline at end of file
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+.pnpm-debug.log*
+
+# Diagnostic reports (https://nodejs.org/api/report.html)
+report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
+
+# Dependency directories
+node_modules/
+
+# TypeScript cache
+*.tsbuildinfo
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variable files
+.env
+.env.development.local
+.env.test.local
+.env.production.local
+.env.local
+
+# yarn v2
+.yarn/cache
+.yarn/unplugged
+.yarn/build-state.yml
+.yarn/install-state.gz
+.pnp.*
+
+# Turborepo
+.turbo/
+dist/
+build/
+
+# Tesseract
+*.traineddata
+
+# ESLint
+.eslintcache
+
+# VSCode
+.vscode/
\ No newline at end of file
diff --git a/.multi-releaserc b/.multi-releaserc
new file mode 100644
index 0000000..2fa8d60
--- /dev/null
+++ b/.multi-releaserc
@@ -0,0 +1,4 @@
+{
+ "ignorePrivate": false,
+ "ignorePackages": ["packages/**"]
+}
\ No newline at end of file
diff --git a/.prettierrc.json b/.prettierrc.json
deleted file mode 100644
index 32ebab4..0000000
--- a/.prettierrc.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "singleQuote": true,
- "trailingComma": "none"
-}
diff --git a/Dockerfile b/Dockerfile
deleted file mode 100644
index 19881bd..0000000
--- a/Dockerfile
+++ /dev/null
@@ -1,25 +0,0 @@
-FROM node:latest
-
-ENV WIT_AI_TOKEN $WIT_AI_TOKEN
-ENV MONGODB_URI $MONGODB_URI
-ENV DISCORD_TOKEN $DISCORD_TOKEN
-
-# Create app directory and install dependencies
-WORKDIR /usr/src/revanced-helper
-COPY . .
-RUN npm i
-
-# Install the server
-WORKDIR /usr/src/revanced-helper/apps/server/src
-RUN npm i
-
-# Install the client for the server
-WORKDIR /usr/src/revanced-helper/packages/client
-RUN npm i
-
-# Install the bot
-WORKDIR /usr/src/revanced-helper/apps/bot-discord/src
-RUN npm i
-
-WORKDIR /usr/src/revanced-helper
-CMD ["npm", "run", "start"]
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..88003ed
--- /dev/null
+++ b/README.md
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Continuing the legacy of Vanced
+
+
+# 🤖 ReVanced Helper
+
+Bots assisting ReVanced on multiple platforms.
+
+## 👷🏻 Contributing
+
+Thank you for considering! This project is made in TypeScript and we use the [Bun](https://bun.sh) JavaScript runtime.
+
+Please refer to the [documentation](./docs) for more information.
+You can find projects under the [`apis`](./apis/), [`bots`](./bots), and [`packages`](./packages/) directories.
\ No newline at end of file
diff --git a/apis/websocket/.env.example b/apis/websocket/.env.example
new file mode 100755
index 0000000..abfe5e7
--- /dev/null
+++ b/apis/websocket/.env.example
@@ -0,0 +1,2 @@
+# Your Wit.ai token
+WIT_AI_TOKEN="YOUR_TOKEN_HERE"
diff --git a/apis/websocket/.releaserc.js b/apis/websocket/.releaserc.js
new file mode 100644
index 0000000..954c2cf
--- /dev/null
+++ b/apis/websocket/.releaserc.js
@@ -0,0 +1,32 @@
+import defineSubprojectReleaseConfig from '../../semantic-release-config.js'
+
+export default defineSubprojectReleaseConfig({
+ plugins:
+ process.env.RELEASE_WORKFLOW_STEP === 'publish'
+ ? [
+ [
+ '@semantic-release/exec',
+ {
+ publishCmd: 'bun run scripts/trigger-portainer-webhook.ts',
+ },
+ ],
+ ]
+ : [
+ [
+ '@codedependant/semantic-release-docker',
+ {
+ dockerImage: 'revanced-bot-websocket-api',
+ dockerRegistry: 'ghcr.io',
+ dockerProject: 'revanced',
+ dockerContext: '../..',
+ dockerPlatform: ['linux/amd64', 'linux/arm64'],
+ dockerBuildQuiet: false,
+ dockerTags: [
+ '{{#if prerelease.[0]}}dev{{else}}main{{/if}}',
+ '{{#unless prerelease.[0]}}latest{{/unless}}',
+ '{{version}}',
+ ],
+ },
+ ],
+ ],
+})
diff --git a/apis/websocket/CHANGELOG.md b/apis/websocket/CHANGELOG.md
new file mode 100644
index 0000000..27a7cb5
--- /dev/null
+++ b/apis/websocket/CHANGELOG.md
@@ -0,0 +1,92 @@
+# @revanced/bot-websocket-api [1.0.0-dev.11](https://github.com/revanced/revanced-bots/compare/@revanced/bot-websocket-api@1.0.0-dev.10...@revanced/bot-websocket-api@1.0.0-dev.11) (2025-04-04)
+
+
+### Bug Fixes
+
+* **apis/websocket:** attempt to fix missing remote address ([9b2888b](https://github.com/revanced/revanced-bots/commit/9b2888b944ea1d61d31aa5df3536768e9a2dadf8))
+* run projects with `--bun` ([bb2182e](https://github.com/revanced/revanced-bots/commit/bb2182e707fa40c555d56138972eeea28f1b3cf9))
+
+# @revanced/bot-websocket-api [1.0.0-dev.10](https://github.com/revanced/revanced-bots/compare/@revanced/bot-websocket-api@1.0.0-dev.9...@revanced/bot-websocket-api@1.0.0-dev.10) (2025-03-03)
+
+
+### Bug Fixes
+
+* fix typings and formatting ([479812e](https://github.com/revanced/revanced-bots/commit/479812e199b52cdb295a5746e0767306afab3413))
+* update repo url ([a21aa34](https://github.com/revanced/revanced-bots/commit/a21aa348d7f32cd0ee65b371e9594520c0a9d3f1))
+
+# @revanced/bot-websocket-api [1.0.0-dev.9](https://github.com/revanced/revanced-helper/compare/@revanced/bot-websocket-api@1.0.0-dev.8...@revanced/bot-websocket-api@1.0.0-dev.9) (2024-08-03)
+
+
+### Features
+
+* **apis/websocket:** return `true` for data on a `TrainedMessage` packet ([65add4d](https://github.com/revanced/revanced-helper/commit/65add4dfeed2fa067c2c8e2377f7d01d505ade54))
+
+# @revanced/bot-websocket-api [1.0.0-dev.8](https://github.com/revanced/revanced-helper/compare/@revanced/bot-websocket-api@1.0.0-dev.7...@revanced/bot-websocket-api@1.0.0-dev.8) (2024-07-31)
+
+
+### Bug Fixes
+
+* other small issues ([bc437a5](https://github.com/revanced/revanced-helper/commit/bc437a5ec7ce1d339094d608e2a61ac5f460c163))
+
+# @revanced/bot-websocket-api [1.0.0-dev.7](https://github.com/revanced/revanced-helper/compare/@revanced/bot-websocket-api@1.0.0-dev.6...@revanced/bot-websocket-api@1.0.0-dev.7) (2024-07-30)
+
+# @revanced/bot-websocket-api [1.0.0-dev.6](https://github.com/revanced/revanced-helper/compare/@revanced/bot-websocket-api@1.0.0-dev.5...@revanced/bot-websocket-api@1.0.0-dev.6) (2024-07-30)
+
+
+### Bug Fixes
+
+* **bots/discord:** hanging process when disconnecting from API too many times ([d31616e](https://github.com/revanced/revanced-helper/commit/d31616ebcba6f1dcd8bde183bcb8d1adb1501b61))
+
+# @revanced/bot-websocket-api [1.0.0-dev.5](https://github.com/revanced/revanced-helper/compare/@revanced/bot-websocket-api@1.0.0-dev.4...@revanced/bot-websocket-api@1.0.0-dev.5) (2024-07-23)
+
+# @revanced/bot-websocket-api [1.0.0-dev.4](https://github.com/revanced/revanced-helper/compare/@revanced/bot-websocket-api@1.0.0-dev.3...@revanced/bot-websocket-api@1.0.0-dev.4) (2024-07-23)
+
+
+### Bug Fixes
+
+* **apis/websocket:** hardcoded paths in tesseract worker builds ([38e00eb](https://github.com/revanced/revanced-helper/commit/38e00eb4e59c763bd74d27b9b9b482ea66e4dcf4))
+
+# @revanced/bot-websocket-api [1.0.0-dev.3](https://github.com/revanced/revanced-helper/compare/@revanced/bot-websocket-api@1.0.0-dev.2...@revanced/bot-websocket-api@1.0.0-dev.3) (2024-07-23)
+
+
+### Bug Fixes
+
+* **apis/websocket:** build and runtime issues ([89d8ab1](https://github.com/revanced/revanced-helper/commit/89d8ab1ee58278a9a96cdc31c679d0a0a0d865af))
+
+# @revanced/bot-websocket-api [1.0.0-dev.2](https://github.com/revanced/revanced-helper/compare/@revanced/bot-websocket-api@1.0.0-dev.1...@revanced/bot-websocket-api@1.0.0-dev.2) (2024-07-22)
+
+
+### Bug Fixes
+
+* **apis/websocket:** also include tesseract core files in build ([7dfbf6c](https://github.com/revanced/revanced-helper/commit/7dfbf6c92c49100954fa4aca471dce4ab9fd9565))
+
+# @revanced/bot-websocket-api 1.0.0-dev.1 (2024-07-22)
+
+
+### Bug Fixes
+
+* **apis/websocket:** builds not working due to dynamic import requirement ([fc7be22](https://github.com/revanced/revanced-helper/commit/fc7be22c6c15974c7394790e93de2a23a6627153))
+* **apis/websocket:** don't bundle `tesseract.js` ([51a6fb6](https://github.com/revanced/revanced-helper/commit/51a6fb65f0df3409eacffb297430840a0e326989))
+* **apis/websocket:** fix forever stuck Promise ([168f40d](https://github.com/revanced/revanced-helper/commit/168f40def64ca213cd2b549f4bafed4c0e1e3695))
+* **apis/websocket:** fix undefined error ([2f03800](https://github.com/revanced/revanced-helper/commit/2f03800c61c00e59e512567d273a195e605d6736))
+* **apis/websocket:** improve logging and error handling ([b6cbe9d](https://github.com/revanced/revanced-helper/commit/b6cbe9d64c01ff11feab8351fb801bc1aee48325))
+* remove error cb handling for `socket.send()` calls ([29544d4](https://github.com/revanced/revanced-helper/commit/29544d4e0127173465796b7e3c62161f4db59c8b))
+* **types:** fix issues with typings ([669e24c](https://github.com/revanced/revanced-helper/commit/669e24ca8103ea051b4e61160dd0f978e36707ea))
+
+
+### chore
+
+* fix more build issues ([77fefb9](https://github.com/revanced/revanced-helper/commit/77fefb9bef286a22f40a4d76b79c64fcc5a2467f))
+
+
+### Features
+
+* **apis/websocket:** clear old client sessions and instances ([43bd0a0](https://github.com/revanced/revanced-helper/commit/43bd0a021cd885a3d74a1f307ec2935e81d17458))
+* **packages/shared:** add logger factory ([17c6be7](https://github.com/revanced/revanced-helper/commit/17c6be7bee5b5c24fd4a5279e73374b0bb7a6229))
+
+
+### BREAKING CHANGES
+
+* In `@revanced/discord-bot`, its environment variable
+ `DATABASE_URL` has been renamed to `DATABASE_PATH`
+ and the `file:` prefix is no longer needed
diff --git a/apis/websocket/Dockerfile b/apis/websocket/Dockerfile
new file mode 100644
index 0000000..5f63eb9
--- /dev/null
+++ b/apis/websocket/Dockerfile
@@ -0,0 +1,17 @@
+# This file should be triggered from the monorepo root
+FROM oven/bun:latest AS base
+
+FROM base AS build
+
+WORKDIR /build
+COPY . .
+RUN bun install --frozen-lockfile
+RUN cd apis/websocket && bun run build
+
+FROM base AS release
+
+WORKDIR /app
+COPY --from=build /build/apis/websocket/dist /app
+USER 1000:1000
+
+ENTRYPOINT [ "bun", "--bun", "run", "index.js" ]
diff --git a/LICENSE b/apis/websocket/LICENSE
old mode 100644
new mode 100755
similarity index 100%
rename from LICENSE
rename to apis/websocket/LICENSE
diff --git a/apis/websocket/README.md b/apis/websocket/README.md
new file mode 100755
index 0000000..1bdbe4c
--- /dev/null
+++ b/apis/websocket/README.md
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Continuing the legacy of Vanced
+
+
+# 🚙 ReVanced Bot WebSocket API
+
+
+
+The WebSocket API for ReVanced bots utilizing BSON for packet transmission.
+
+## 📚 Documentation
+
+Documentation are provided [here](./docs/README.md).
+
+## 📄 License
+
+**ReVanced Bot WebSocket API** adopts the [GNU General Public License 3.0](./LICENSE), tl;dr: You may copy, distribute and modify the software as long as you track changes/dates in source files. Any modifications to or software including (via compiler) GPL-licensed code must also be made available under the GPL along with build & install instructions.
diff --git a/apis/websocket/config.json b/apis/websocket/config.json
new file mode 100755
index 0000000..2b929d4
--- /dev/null
+++ b/apis/websocket/config.json
@@ -0,0 +1,8 @@
+{
+ "$schema": "./config.schema.json",
+
+ "address": "127.0.0.1",
+ "port": 3000,
+ "ocrConcurrentQueues": 1,
+ "logLevel": "debug"
+}
diff --git a/apis/websocket/config.schema.json b/apis/websocket/config.schema.json
new file mode 100755
index 0000000..a6343ef
--- /dev/null
+++ b/apis/websocket/config.schema.json
@@ -0,0 +1,27 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "type": "object",
+ "properties": {
+ "address": {
+ "description": "Address to listen on",
+ "type": "string",
+ "default": "127.0.0.1"
+ },
+ "port": {
+ "description": "Port to listen on",
+ "type": "integer",
+ "default": 80
+ },
+ "ocrConcurrentQueues": {
+ "description": "Number of concurrent queues for OCR",
+ "type": "integer",
+ "default": 1
+ },
+ "logLevel": {
+ "description": "The log level to print to console",
+ "type": "string",
+ "enum": ["error", "warn", "info", "log", "debug", "trace", "none"],
+ "default": "info"
+ }
+ }
+}
diff --git a/apis/websocket/docker-compose.example.yml b/apis/websocket/docker-compose.example.yml
new file mode 100644
index 0000000..17cddce
--- /dev/null
+++ b/apis/websocket/docker-compose.example.yml
@@ -0,0 +1,11 @@
+services:
+ websocket-api:
+ container_name: revanced-bot-websocket-api
+ image: ghcr.io/revanced/revanced-bot-websocket-api:latest
+ environment:
+ - WIT_AI_TOKEN=
+ volumes:
+ - /data/revanced-bot-websocket-api:/app
+ ports:
+ - 3000:3000
+ restart: unless-stopped
diff --git a/apis/websocket/docs/1_configuration.md b/apis/websocket/docs/1_configuration.md
new file mode 100644
index 0000000..3becf24
--- /dev/null
+++ b/apis/websocket/docs/1_configuration.md
@@ -0,0 +1,45 @@
+# ⚙️ Configuration
+
+This is the default configuration (provided in [config.json](../config.json)):
+
+```json
+{
+ "address": "127.0.0.1",
+ "port": 3000,
+ "ocrConcurrentQueues": 1,
+ "consoleLogLevel": "log"
+}
+```
+
+---
+
+### `config.address` & `config.port`
+
+The address and port for the server to listen on.
+
+### `config.ocrConcurrentQueues`
+
+Amount of concurrent queues that can be run at a time.
+
+> [!WARNING]
+> Setting this too high may cause performance issues.
+
+### `config.logLevel`
+
+The level of logs to print to console. If the level is more important or equally important to set level, it will be forwarded to the console.
+
+The possible levels (sorted by their importance descendingly) are:
+
+- `none` (no messages)
+- `fatal`
+- `error`
+- `warn`
+- `info`
+- `log`
+- `debug`
+
+## ⏭️ What's next
+
+The next page will tell you how to run and bundle the server.
+
+Continue: [🏃🏻♂️ Running the server](./2_running_and_deploying.md)
diff --git a/apis/websocket/docs/2_running_and_deploying.md b/apis/websocket/docs/2_running_and_deploying.md
new file mode 100644
index 0000000..08dafc9
--- /dev/null
+++ b/apis/websocket/docs/2_running_and_deploying.md
@@ -0,0 +1,58 @@
+# 🏃🏻♂️ Running and deploying the server
+
+There are many methods to run the server. Choose one that suits best for the situation.
+
+## 👷🏻 Development mode
+
+There will be no compilation step, and Bun will automatically watch changes and restart the server for you.
+
+You can quickly start the server by running:
+
+```sh
+bun dev
+```
+
+## 📦 Building
+
+If you're looking to build and host the server somewhere else, you can run:
+
+```sh
+bun run build
+```
+
+The distribution files will be placed inside the `dist` directory. Inside will include:
+
+- The default configuration for the API
+- Compiled source files of the API
+
+## ✈️ Deploying
+
+To deploy the API, you'll need to:
+
+1. [Build the API as seen in the previous step](#-building)
+
+2. Copy contents of the `dist` directory
+
+ ```sh
+ # For instance, we'll copy them both to /usr/src/api
+ cp -R ./dist/* /usr/src/api
+ ```
+
+3. Replace the default configuration *(optional)*
+
+4. Configure environment variables
+ As seen in [`.env.example`](../.env.example). You can also optionally use a `.env` file which **Bun will automatically load**.
+ It is recommended to set `NODE_ENV` to `production` when deploying production builds.
+
+5. Finally, you can run the API using these commands
+
+ ```sh
+ cd /usr/src/api
+ bun run index.js
+ ```
+
+## ⏭️ What's next
+
+The next page will tell you about packets.
+
+Continue: [📨 Packets](./3_packets.md)
diff --git a/apis/websocket/docs/3_packets.md b/apis/websocket/docs/3_packets.md
new file mode 100644
index 0000000..e2d64b1
--- /dev/null
+++ b/apis/websocket/docs/3_packets.md
@@ -0,0 +1,31 @@
+# 📨 Packets
+
+Packets are BSON messages sent to the server. They're structured like the following when decoded:
+
+```json
+{
+ "op": 12345,
+ "d": {
+ "some_field": "some data"
+ }
+}
+```
+
+### `packet.op`
+
+Operation codes are numbers that communicate an action.
+
+### `packet.d`
+
+Data fields include additional information for the server to process. They are **either an object with specific fields or just `null`**.
+
+### `packet.s` (server packets)
+
+A sequence number, exclusively for server packets. The WebSocket server contacts other APIs and they may not be reliable at all times, this makes race conditions. A sequence number cleanly solves this issue by letting the client know what the next packet sequence number would be by giving the current number.
+
+#### 📦 Schemas and constants
+
+Schemas for packets and their respective data[^1], and the list of possible operation codes[^2] can be found in the `@revanced/bot-shared` package, with typings as well.
+
+[^1]: [`@revanced/bot-shared/src/schemas/Packet.ts`](../../../packages/shared/src/schemas/Packet.ts)
+[^2]: [`@revanced/bot-shared/src/constants/Operation`](../../../packages/shared/src/constants/Operation.ts)
diff --git a/apis/websocket/docs/README.md b/apis/websocket/docs/README.md
new file mode 100755
index 0000000..710432d
--- /dev/null
+++ b/apis/websocket/docs/README.md
@@ -0,0 +1,16 @@
+# 🚙 ReVanced Bot WebSocket API
+
+This documentation explains how the server works, how to start developing, and how to configure the server.
+
+## 📖 Table of contents
+
+0. [🏗️ Set up the development environment (if you haven't already)](../../../docs/0_development_environment.md)
+1. [⚙️ Configuration](./1_configuration.md)
+2. [🏃🏻♂️ Running the server](./2_running.md)
+3. [📨 Packets](./3_packets.md)
+
+## ⏭️ Start here
+
+The next page will tell you how to configure the server.
+
+Continue: [⚙️ Configuration](./1_configuration.md)
diff --git a/apis/websocket/package.json b/apis/websocket/package.json
new file mode 100755
index 0000000..346de4a
--- /dev/null
+++ b/apis/websocket/package.json
@@ -0,0 +1,40 @@
+{
+ "name": "@revanced/bot-websocket-api",
+ "type": "module",
+ "private": true,
+ "version": "1.0.0-dev.11",
+ "description": "🧦 WebSocket API server for bots assisting ReVanced",
+ "main": "dist/index.js",
+ "scripts": {
+ "bundle": "bun run scripts/build.ts",
+ "dev": "bun run src/index.ts --watch",
+ "build": "bun bundle",
+ "watch": "bun dev"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/revanced/revanced-bots.git",
+ "directory": "apis/websocket"
+ },
+ "author": "Palm (https://palmdevs.me)",
+ "contributors": [
+ "Palm (https://palmdevs.me)",
+ "ReVanced (https://revanced.app)"
+ ],
+ "license": "GPL-3.0-or-later",
+ "bugs": {
+ "url": "https://github.com/revanced/revanced-bots/issues"
+ },
+ "homepage": "https://github.com/revanced/revanced-bots#readme",
+ "dependencies": {
+ "@revanced/bot-shared": "workspace:*",
+ "@sapphire/async-queue": "^1.5.5",
+ "chalk": "^5.4.1",
+ "tesseract.js": "^5.1.1",
+ "ws": "^8.18.1"
+ },
+ "devDependencies": {
+ "@types/ws": "^8.18.1",
+ "typed-emitter": "^2.1.0"
+ }
+}
\ No newline at end of file
diff --git a/apis/websocket/scripts/build.ts b/apis/websocket/scripts/build.ts
new file mode 100644
index 0000000..cfdf7be
--- /dev/null
+++ b/apis/websocket/scripts/build.ts
@@ -0,0 +1,32 @@
+import { createLogger } from '@revanced/bot-shared'
+import { cp, exists, rm } from 'fs/promises'
+
+const logger = createLogger()
+
+logger.info('Cleaning previous build...')
+if (await exists('./dist')) await rm('./dist', { recursive: true })
+
+logger.info('Building WebSocket API...')
+await Bun.build({
+ entrypoints: ['./src/index.ts'],
+ outdir: './dist',
+ target: 'bun',
+ sourcemap: 'external',
+})
+
+logger.info('Building Tesseract.js worker...')
+await Bun.build({
+ entrypoints: ['../../node_modules/tesseract.js/src/worker-script/node/index.js'],
+ external: ['tesseract.js-core/*'],
+ target: 'bun',
+ outdir: './dist/worker',
+ sourcemap: 'external',
+})
+
+// Tesseract.js is really bad for minification
+// It forcefully requires this core module to be present which contains the WASM files
+logger.info('Copying Tesseract.js Core...')
+await cp('../../node_modules/tesseract.js-core', './dist/node_modules/tesseract.js-core', { recursive: true })
+
+logger.info('Copying config...')
+await cp('config.json', 'dist/config.json')
diff --git a/apis/websocket/scripts/trigger-portainer-webhook.ts b/apis/websocket/scripts/trigger-portainer-webhook.ts
new file mode 100644
index 0000000..a8d89bb
--- /dev/null
+++ b/apis/websocket/scripts/trigger-portainer-webhook.ts
@@ -0,0 +1,4 @@
+import { $ } from 'bun'
+
+const URLEnvironmentVariableName = 'WEBSOCKET_API_PORTAINER_WEBHOOK_URL'
+await $`INPUT_WEBHOOK_URL=${process.env[URLEnvironmentVariableName]} bun run ../../node_modules/portainer-service-webhook/dist`
diff --git a/apis/websocket/src/classes/Client.ts b/apis/websocket/src/classes/Client.ts
new file mode 100755
index 0000000..2299fcd
--- /dev/null
+++ b/apis/websocket/src/classes/Client.ts
@@ -0,0 +1,137 @@
+import { EventEmitter } from 'events'
+import {
+ ClientOperation,
+ DisconnectReason,
+ type Packet,
+ ServerOperation,
+ deserializePacket,
+ isClientPacket,
+ serializePacket,
+ uncapitalize,
+} from '@revanced/bot-shared'
+
+import type TypedEmitter from 'typed-emitter'
+import type { RawData, WebSocket } from 'ws'
+
+export default class Client {
+ id: string
+ disconnected: DisconnectReason | false = false
+ ready = false
+ currentSequence = 0
+
+ #emitter = new EventEmitter() as TypedEmitter
+ #socket: WebSocket
+
+ constructor(options: ClientOptions) {
+ this.#socket = options.socket
+ this.id = options.id
+
+ this.#socket.on('error', () => this.disconnect(DisconnectReason.ServerError))
+ this.#socket.on('close', code => this._handleDisconnect(code))
+ this.#socket.on('unexpected-response', () => this.disconnect(DisconnectReason.InvalidPacket))
+
+ this.send({
+ op: ServerOperation.Hello,
+ d: null,
+ })
+
+ this._listen()
+ this.ready = true
+ this.#emitter.emit('ready')
+ }
+
+ on(name: T, handler: ClientEventHandlers[typeof name]) {
+ this.#emitter.on(name, handler)
+ }
+
+ once(name: T, handler: ClientEventHandlers[typeof name]) {
+ this.#emitter.once(name, handler)
+ }
+
+ off(name: T, handler: ClientEventHandlers[typeof name]) {
+ this.#emitter.off(name, handler)
+ }
+
+ send(packet: Omit, 's'>, sequence?: number) {
+ this.#throwIfDisconnected('Cannot send packet to client that has already disconnected')
+ this.#socket.send(serializePacket({ ...packet, s: sequence ?? this.currentSequence++ } as Packet), err => {
+ if (err) throw err
+ })
+ }
+
+ async disconnect(reason: DisconnectReason | number = DisconnectReason.Generic) {
+ this.#throwIfDisconnected('Cannot disconnect client that has already disconnected')
+
+ this.#socket.close(reason)
+ this._handleDisconnect(reason)
+ }
+
+ #throwIfDisconnected(errorMessage: string) {
+ if (this.disconnected !== false) throw new Error(errorMessage)
+
+ if (this.#socket.readyState !== this.#socket.OPEN) {
+ this.#socket.close(DisconnectReason.NoOpenSocket)
+ throw new Error(errorMessage)
+ }
+ }
+
+ protected _handleDisconnect(code: number) {
+ this.disconnected = code
+ this.ready = false
+
+ this.#emitter.emit('disconnect', code)
+ }
+
+ protected _listen() {
+ this.#socket.on('message', data => {
+ this.#emitter.emit('message', data)
+ try {
+ const rawPacket = deserializePacket(this._toBuffer(data))
+ if (!isClientPacket(rawPacket)) throw null
+
+ const packet: ClientPacketObject = {
+ ...rawPacket,
+ client: this,
+ }
+
+ this.#emitter.emit('packet', packet)
+ this.#emitter.emit(
+ uncapitalize(ClientOperation[packet.op] as ClientEventName),
+ // @ts-expect-error TypeScript doesn't know that the above line will negate the type enough
+ packet,
+ )
+ } catch (e) {
+ // TODO: add error fields to sent packet so we can log what went wrong
+ this.disconnect(DisconnectReason.InvalidPacket)
+ }
+ })
+ }
+
+ protected _toBuffer(data: RawData) {
+ if (data instanceof Buffer) return data
+ if (data instanceof ArrayBuffer) return Buffer.from(data)
+ return Buffer.concat(data as Uint8Array[])
+ }
+}
+
+export interface ClientOptions {
+ id: string
+ socket: WebSocket
+}
+
+export type ClientPacketObject = Packet & {
+ client: Client
+}
+
+export type ClientEventName = keyof typeof ClientOperation
+
+export type ClientEventHandlers = {
+ [K in Uncapitalize]: (
+ packet: ClientPacketObject<(typeof ClientOperation)[Capitalize]>,
+ ) => Promise | unknown
+} & {
+ ready: () => Promise | unknown
+ packet: (packet: ClientPacketObject) => Promise | unknown
+ disconnect: (reason: DisconnectReason) => Promise | unknown
+ message: (data: RawData) => Promise | unknown
+}
diff --git a/apis/websocket/src/context.ts b/apis/websocket/src/context.ts
new file mode 100644
index 0000000..033f473
--- /dev/null
+++ b/apis/websocket/src/context.ts
@@ -0,0 +1,63 @@
+import { OEM, createWorker as createTesseractWorker } from 'tesseract.js'
+
+import { join as joinPath } from 'path'
+import { createLogger } from '@revanced/bot-shared'
+import { exists as pathExists } from 'fs/promises'
+import { getConfig } from './utils/config'
+
+export const config = getConfig()
+
+export const logger = createLogger({
+ level: config.logLevel === 'none' ? Number.MAX_SAFE_INTEGER : config.logLevel,
+})
+
+export const wit = {
+ token: process.env['WIT_AI_TOKEN']!,
+ async fetch(route: string, options?: RequestInit) {
+ const res = await fetch(`https://api.wit.ai${route}`, {
+ headers: {
+ Authorization: `Bearer ${this.token}`,
+ 'Content-Type': 'application/json',
+ },
+ ...options,
+ })
+
+ if (!res.ok) throw new Error(`Failed to fetch from Wit.ai: ${res.statusText} (${res.status})`)
+
+ return await res.json()
+ },
+ message(text: string) {
+ return this.fetch(`/message?q=${encodeURIComponent(text)}&n=8`) as Promise
+ },
+ async train(text: string, label: string) {
+ await this.fetch('/utterances', {
+ body: JSON.stringify([
+ {
+ text,
+ intent: label,
+ entities: [],
+ traits: [],
+ },
+ ]),
+ method: 'POST',
+ })
+ },
+} as const
+
+export interface WitMessageResponse {
+ text: string
+ intents: Array<{
+ id: string
+ name: string
+ confidence: number
+ }>
+}
+
+const TesseractWorkerDirPath = joinPath(import.meta.dir, 'worker')
+const TesseractWorkerPath = joinPath(TesseractWorkerDirPath, 'index.js')
+
+export const tesseract = await createTesseractWorker(
+ 'eng',
+ OEM.DEFAULT,
+ (await pathExists(TesseractWorkerDirPath)) ? { workerPath: TesseractWorkerPath } : undefined,
+)
diff --git a/apis/websocket/src/events/index.ts b/apis/websocket/src/events/index.ts
new file mode 100755
index 0000000..4c5778d
--- /dev/null
+++ b/apis/websocket/src/events/index.ts
@@ -0,0 +1,25 @@
+import type { ClientOperation } from '@revanced/bot-shared'
+import type { Logger } from '@revanced/bot-shared'
+import type { Worker as TesseractWorker } from 'tesseract.js'
+import type { ClientPacketObject } from '../classes/Client'
+import type { WitMessageResponse } from '../context'
+import type { Config } from '../utils/config'
+
+export { default as parseTextEventHandler } from './parseText'
+export { default as parseImageEventHandler } from './parseImage'
+export { default as trainMessageEventHandler } from './trainMessage'
+
+export type EventHandler = (
+ packet: ClientPacketObject,
+ context: EventContext,
+) => void | Promise
+
+export type EventContext = {
+ wit: {
+ train(text: string, label: string): Promise
+ message(text: string): Promise
+ }
+ tesseract: TesseractWorker
+ logger: Logger
+ config: Config
+}
diff --git a/apis/websocket/src/events/parseImage.ts b/apis/websocket/src/events/parseImage.ts
new file mode 100755
index 0000000..cc0bd2f
--- /dev/null
+++ b/apis/websocket/src/events/parseImage.ts
@@ -0,0 +1,56 @@
+import { type ClientOperation, ServerOperation } from '@revanced/bot-shared'
+import { AsyncQueue } from '@sapphire/async-queue'
+
+import type { EventHandler } from '.'
+
+const queue = new AsyncQueue()
+
+const parseImageEventHandler: EventHandler = async (
+ packet,
+ { tesseract, logger, config },
+) => {
+ const {
+ client,
+ d: { image_url: imageUrl },
+ } = packet
+
+ const nextSeq = client.currentSequence++
+
+ logger.debug(`Client ${client.id} requested to parse image from URL (${nextSeq})`, imageUrl)
+
+ if (queue.remaining < config.ocrConcurrentQueues) queue.shift()
+ await queue.wait()
+
+ logger.debug(`Process queued (${nextSeq}), queue has ${queue.remaining} items`)
+
+ try {
+ const { data, jobId } = await tesseract.recognize(imageUrl)
+
+ logger.debug(`Image parsed (job ${jobId}) (${nextSeq}):`, data.text)
+ client.send(
+ {
+ op: ServerOperation.ParsedImage,
+ d: {
+ text: data.text,
+ },
+ },
+ nextSeq,
+ )
+ } catch (e) {
+ if (!client.disconnected)
+ client.send(
+ {
+ op: ServerOperation.ParseImageFailed,
+ d: null,
+ },
+ nextSeq,
+ )
+ else logger.warn(`Client disconnected before the failed packet could be sent (${nextSeq})`)
+ logger.error(`Failed to parse image (${nextSeq}):`, e)
+ } finally {
+ queue.shift()
+ logger.debug(`Finished parsing image (${nextSeq}), queue has ${queue.remaining} items`)
+ }
+}
+
+export default parseImageEventHandler
diff --git a/apis/websocket/src/events/parseText.ts b/apis/websocket/src/events/parseText.ts
new file mode 100755
index 0000000..fa3e645
--- /dev/null
+++ b/apis/websocket/src/events/parseText.ts
@@ -0,0 +1,43 @@
+import { type ClientOperation, ServerOperation } from '@revanced/bot-shared'
+
+import type { EventHandler } from '.'
+
+const parseTextEventHandler: EventHandler = async (packet, { wit, logger }) => {
+ const {
+ client,
+ d: { text },
+ } = packet
+
+ const nextSeq = client.currentSequence++
+ const actualText = text.slice(0, 279)
+
+ logger.debug(`Client ${client.id} requested to parse text:`, actualText)
+
+ try {
+ const { intents } = await wit.message(actualText)
+ const intentsWithoutIds = intents.map(({ id, ...rest }) => rest)
+
+ client.send(
+ {
+ op: ServerOperation.ParsedText,
+ d: {
+ labels: intentsWithoutIds,
+ },
+ },
+ nextSeq,
+ )
+ } catch (e) {
+ if (!client.disconnected)
+ client.send(
+ {
+ op: ServerOperation.ParseTextFailed,
+ d: null,
+ },
+ nextSeq,
+ )
+ else logger.warn(`Client disconnected before the failed packet could be sent (${nextSeq})`)
+ logger.error(`Failed to parse text (${nextSeq}):`, e)
+ }
+}
+
+export default parseTextEventHandler
diff --git a/apis/websocket/src/events/trainMessage.ts b/apis/websocket/src/events/trainMessage.ts
new file mode 100644
index 0000000..1e70982
--- /dev/null
+++ b/apis/websocket/src/events/trainMessage.ts
@@ -0,0 +1,41 @@
+import { type ClientOperation, ServerOperation } from '@revanced/bot-shared'
+
+import type { EventHandler } from '.'
+
+const trainMessageEventHandler: EventHandler = async (packet, { wit, logger }) => {
+ const {
+ client,
+ d: { text, label },
+ } = packet
+
+ const nextSeq = client.currentSequence++
+ const actualText = text.slice(0, 279)
+
+ logger.debug(`${client.id} requested to train label ${label} (${nextSeq}) with:`, actualText)
+
+ try {
+ await wit.train(actualText, label)
+ client.send(
+ {
+ op: ServerOperation.TrainedMessage,
+ d: true,
+ },
+ nextSeq,
+ )
+
+ logger.debug(`Trained label (${nextSeq})`)
+ } catch (e) {
+ if (!client.disconnected)
+ client.send(
+ {
+ op: ServerOperation.TrainMessageFailed,
+ d: null,
+ },
+ nextSeq,
+ )
+ else logger.warn(`Client ${client.id} disconnected before the failed packet could be sent`)
+ logger.error(`Failed to train (${nextSeq})`, e)
+ }
+}
+
+export default trainMessageEventHandler
diff --git a/apis/websocket/src/index.ts b/apis/websocket/src/index.ts
new file mode 100755
index 0000000..23df4a5
--- /dev/null
+++ b/apis/websocket/src/index.ts
@@ -0,0 +1,132 @@
+import { inspect as inspectObject } from 'util'
+
+import Client from './classes/Client'
+
+import { type EventContext, parseImageEventHandler, parseTextEventHandler, trainMessageEventHandler } from './events'
+
+import { DisconnectReason, HumanizedDisconnectReason } from '@revanced/bot-shared'
+
+import { createServer } from 'http'
+import { type WebSocket, WebSocketServer } from 'ws'
+import { config, logger, tesseract, wit } from './context'
+
+// Load config, init logger, check environment
+
+if (!process.env['NODE_ENV']) logger.warn('NODE_ENV not set, defaulting to `development`')
+const environment = (process.env['NODE_ENV'] ?? 'development') as NodeEnvironment
+
+if (!['development', 'production'].includes(environment)) {
+ logger.error('NODE_ENV is neither `development` nor `production`, unable to determine environment')
+ logger.info('Set NODE_ENV to blank to use `development` mode')
+ process.exit(1)
+}
+
+logger.info(`Running in ${environment} mode...`)
+
+if (!process.env['WIT_AI_TOKEN']) {
+ logger.error('WIT_AI_TOKEN is not defined in the environment variables')
+ process.exit(1)
+}
+
+// Handle uncaught exceptions
+
+process.on('uncaughtException', e => logger.error('Uncaught exception:', e))
+process.on('unhandledRejection', e => logger.error('Unhandled rejection:', e))
+
+// Server logic
+
+const clientIds = new Set()
+const clientToSocket = new WeakMap()
+const socketToClient = new WeakMap()
+const eventContext: EventContext = {
+ tesseract,
+ logger,
+ wit,
+ config,
+}
+
+const server = createServer()
+const wss = new WebSocketServer({
+ // 16 KiB max payload
+ // A Discord message can not be longer than 4000 characters
+ // OCR should not be longer than 16000 characters
+ maxPayload: 16 * 1024,
+ server,
+})
+
+wss.on('connection', async (socket, request) => {
+ try {
+ const addrInfo = request.socket.address()
+ if (!('address' in addrInfo)) {
+ socket.close()
+ return logger.warn('Connection failed because client is missing remote address. addrInfo =', addrInfo)
+ }
+
+ const id = `${addrInfo.address}:${addrInfo.port}`
+
+ if (clientIds.has(id)) {
+ logger.warn(`Client ${id} already connected, disconnecting old session`)
+ const oldClient = socketToClient.get(socket)
+ await oldClient?.disconnect(DisconnectReason.NewConnection)
+ }
+
+ const client = new Client({
+ socket,
+ id,
+ })
+
+ socketToClient.set(socket, client)
+ clientToSocket.set(client, socket)
+
+ logger.info(`New client connected with ID: ${id}`)
+
+ client.on('disconnect', reason => {
+ clientIds.delete(client.id)
+ clientToSocket.delete(client)
+ socketToClient.delete(socket)
+
+ logger.info(
+ `Client ${client.id} disconnected because client ${HumanizedDisconnectReason[reason]} (${reason})`,
+ )
+ })
+
+ client.on('parseText', packet => parseTextEventHandler(packet, eventContext))
+ client.on('parseImage', packet => parseImageEventHandler(packet, eventContext))
+ client.on('trainMessage', packet => trainMessageEventHandler(packet, eventContext))
+
+ if (['debug', 'trace'].includes(config.logLevel)) {
+ logger.debug('Debug logs enabled, attaching debug events...')
+
+ client.on('message', d => logger.debug(`Message from client ${client.id}:`, d))
+ client.on('packet', ({ client, ...rawPacket }) =>
+ logger.debug(`Packet received from client ${client.id}: ${inspectObject(rawPacket)}`),
+ )
+ }
+ } catch (e) {
+ if (e instanceof Error) logger.error(e.stack ?? e.message)
+ else logger.error(inspectObject(e))
+
+ const client = socketToClient.get(socket)
+
+ if (!client) {
+ logger.error(
+ 'Missing client instance when encountering an error. If the instance still exists in memory, it will NOT be removed!',
+ )
+ return socket.terminate()
+ }
+
+ if (client.disconnected === false) client.disconnect(DisconnectReason.ServerError)
+
+ logger.debug(`Client ${client.id} disconnected because of an internal error`)
+ }
+})
+
+// Start the server
+
+server.listen(config.port, config.address)
+logger.debug(`Starting with these configurations: ${inspectObject(config)}`)
+
+const addressInfo = wss.address()
+if (!addressInfo || typeof addressInfo !== 'object')
+ logger.debug('Server started, but cannot determine address information')
+else logger.info(`Server started at: ${addressInfo.address}:${addressInfo.port}`)
diff --git a/apis/websocket/src/types.d.ts b/apis/websocket/src/types.d.ts
new file mode 100755
index 0000000..41da923
--- /dev/null
+++ b/apis/websocket/src/types.d.ts
@@ -0,0 +1,9 @@
+declare global {
+ namespace NodeJS {
+ interface ProcessEnv {
+ WIT_AI_TOKEN?: string
+ }
+ }
+}
+
+declare type NodeEnvironment = 'development' | 'production'
diff --git a/apis/websocket/src/utils/config.ts b/apis/websocket/src/utils/config.ts
new file mode 100755
index 0000000..4415c0d
--- /dev/null
+++ b/apis/websocket/src/utils/config.ts
@@ -0,0 +1,36 @@
+import { existsSync } from 'fs'
+import { resolve as resolvePath } from 'path'
+import { pathToFileURL } from 'url'
+
+const configPath = resolvePath(process.cwd(), 'config.json')
+
+const userConfig: Partial = existsSync(configPath)
+ ? (
+ await import(pathToFileURL(configPath).href, {
+ with: {
+ type: 'json',
+ },
+ })
+ ).default
+ : {}
+
+type BaseTypeOf = T extends (infer U)[]
+ ? U[]
+ : T extends (...args: unknown[]) => infer U
+ ? (...args: unknown[]) => U
+ : T extends object
+ ? { [K in keyof T]: T[K] }
+ : T
+
+export type Config = Omit, '$schema'>
+
+export const defaultConfig: Config = {
+ address: '127.0.0.1',
+ port: 8080,
+ ocrConcurrentQueues: 1,
+ logLevel: 'info',
+}
+
+export function getConfig() {
+ return Object.assign(defaultConfig, userConfig) satisfies Config
+}
diff --git a/apis/websocket/tsconfig.json b/apis/websocket/tsconfig.json
new file mode 100755
index 0000000..1810ebe
--- /dev/null
+++ b/apis/websocket/tsconfig.json
@@ -0,0 +1,15 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "baseUrl": ".",
+ "outDir": "dist",
+ "module": "ESNext",
+ "target": "ESNext",
+ "lib": ["ESNext"],
+ "composite": false,
+ "skipLibCheck": true,
+ "resolveJsonModule": true
+ },
+ "exclude": ["node_modules", "dist"],
+ "include": ["./*.json", "src/**/*.ts", "scripts/**/*.ts"]
+}
diff --git a/apps/bot-discord/src/commands/ban.js b/apps/bot-discord/src/commands/ban.js
deleted file mode 100644
index 5ca51c3..0000000
--- a/apps/bot-discord/src/commands/ban.js
+++ /dev/null
@@ -1,45 +0,0 @@
-import { SlashCommandBuilder } from 'discord.js';
-import { checkForPerms } from '../utils/checkModPerms.js';
-import reportToLogs from '../utils/reportToLogs.js';
-
-export default {
- data: new SlashCommandBuilder()
- .setName('ban')
- .setDescription('Ban a member.')
- .setDMPermission(false)
- .addUserOption(option =>
- option
- .setName('user')
- .setDescription('The member to ban')
- .setRequired(true)
- )
- .addIntegerOption(option =>
- option
- .setName('dmd')
- .setDescription('Amount of days to delete messages')
- )
- .addStringOption(option =>
- option
- .setName('reason')
- .setDescription('Reason for the ban')
- ),
- async execute(_, config, interaction) {
- if (!checkForPerms(config, interaction.member)) return interaction.reply({
- epheremal: true,
- content: 'You don\'t have the required permissions.'
- });
-
- interaction.guild.members.ban(interaction.options.getUser('user'), {
- reason: interaction.options.getString('reason'),
- deleteMessageSeconds: interaction.options.getString('dmd') ?
- interaction.options.getString('dmd') * 86_400 : 0
- });
-
- reportToLogs(config, interaction.client, 'banned', null, {
- reason: interaction.options.getString('reason'),
- actionTo: interaction.options.getUser('user'),
- actionBy: interaction.member,
- channel: interaction.channel
- }, interaction);
- }
-};
diff --git a/apps/bot-discord/src/commands/exile.js b/apps/bot-discord/src/commands/exile.js
deleted file mode 100644
index 9ed8f41..0000000
--- a/apps/bot-discord/src/commands/exile.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import { SlashCommandBuilder } from 'discord.js';
-import { checkForPerms } from '../utils/checkSupporterPerms.js'
-import reportToLogs from '../utils/reportToLogs.js';
-import muteMember from '../utils/muteMember.js';
-import exileMemberToChannel from '../utils/exileMemberToChannel.js';
-
-export default {
- data: new SlashCommandBuilder()
- .setName('exile')
- .setDescription('Exile a member to support.')
- .setDMPermission(false)
- .addUserOption(option =>
- option
- .setName('user')
- .setDescription('The member to exile')
- .setRequired(true)
- )
- .addStringOption(option =>
- option
- .setName('reason')
- .setDescription('The reason of the exile')
- .setRequired(true)
- ),
- async execute(_, config, interaction) {
- if (!checkForPerms(config, interaction.member)) return interaction.reply({
- epheremal: true,
- content: 'You don\'t have the required permissions.'
- });
-
- await interaction.deferReply();
-
- const user = interaction.options.getUser('user');
-
- const member = await interaction.guild.members.fetch(user);
- const reason = interaction.options.getString('reason');
- const parsedDuration = await muteMember(config, member, {
- reason,
- supportMute: true,
- guild: interaction.guild
- });
-
- exileMemberToChannel(member, interaction.channel, null, reason, config);
-
- reportToLogs(config, interaction.client, 'exiled', null, {
- reason,
- actionTo: user,
- actionBy: interaction.member,
- channel: interaction.channel,
- expire: parsedDuration
- }, interaction);
- }
-};
diff --git a/apps/bot-discord/src/commands/exileMemberCtx.js b/apps/bot-discord/src/commands/exileMemberCtx.js
deleted file mode 100644
index 77a8b62..0000000
--- a/apps/bot-discord/src/commands/exileMemberCtx.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import { ContextMenuCommandBuilder, ApplicationCommandType } from 'discord.js';
-import { checkForPerms } from '../utils/checkSupporterPerms.js'
-import muteMember from '../utils/muteMember.js';
-import exileMemberToChannel from '../utils/exileMemberToChannel.js';
-import reportToLogs from '../utils/reportToLogs.js';
-
-export default {
- data: new ContextMenuCommandBuilder()
- .setName('Exile Member')
- .setType(ApplicationCommandType.Message),
- async execute(helper, config, interaction) {
- if (
- !checkForPerms(config, interaction.member)
- )
- return interaction.reply({
- content: 'You don\'t have the permission to do this.',
- ephemeral: true
- });
-
- await interaction.deferReply();
- const targetMsg = interaction.targetMessage;
-
- const member = await interaction.guild.members.fetch(targetMsg.author.id);
- const parsedDuration = await muteMember(config, member, {
- channel: interaction.channel,
- reason: null,
- supportMute: true,
- guild: interaction.guild
- });
-
- exileMemberToChannel(targetMsg.author, interaction.channel, targetMsg.content, null, config);
-
- reportToLogs(config, interaction.client, 'exiled', null, {
- reason: null,
- actionTo: targetMsg.author,
- actionBy: interaction.member,
- channel: interaction.channel,
- expire: parsedDuration
- }, interaction);
-
- await targetMsg.delete();
- }
-};
diff --git a/apps/bot-discord/src/commands/feedbackDislike.js b/apps/bot-discord/src/commands/feedbackDislike.js
deleted file mode 100644
index 8b9e5ba..0000000
--- a/apps/bot-discord/src/commands/feedbackDislike.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import { checkForPerms } from '../utils/checkSupporterPerms.js';
-import trainAISelectMenu from '../utils/trainAISelectMenu.js';
-
-export default {
- data: {
- name: 'fb-dislike'
- },
- async execute(helper, config, interaction) {
- if (
- !checkForPerms(config, interaction.member)
- )
- return interaction.reply({
- content: 'You don\'t have the permission to do this.',
- ephemeral: true
- });
-
- trainAISelectMenu(interaction, config, helper);
- }
-};
diff --git a/apps/bot-discord/src/commands/feedbackLike.js b/apps/bot-discord/src/commands/feedbackLike.js
deleted file mode 100644
index 82e5a16..0000000
--- a/apps/bot-discord/src/commands/feedbackLike.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import { checkForPerms } from '../utils/checkSupporterPerms.js';
-
-export default {
- data: {
- name: 'fb-like'
- },
- async execute(helper, config, interaction) {
- if (
- !checkForPerms(config, interaction.member)
- )
- return interaction.reply({
- content: 'You don\'t have the permission to do this.',
- ephemeral: true
- });
- // FIXME: somehow get the intent?
- // maybe storing in a collection and fetching the msg id with its label?
- /*
- helper.sendTrainData(interactedMessage, i.values[0]);
-
- i.reply({ content: 'Sent training data to server.', ephemeral: true });
-
- interaction.message.edit({ components: [] });
- */
- interaction.reply({
- content: 'Feature currently not available. Please use the dislike button.',
- ephemeral: true
- });
- }
-};
diff --git a/apps/bot-discord/src/commands/mute.js b/apps/bot-discord/src/commands/mute.js
deleted file mode 100644
index 6a4b9a0..0000000
--- a/apps/bot-discord/src/commands/mute.js
+++ /dev/null
@@ -1,56 +0,0 @@
-import { SlashCommandBuilder } from 'discord.js';
-import { checkForPerms } from '../utils/checkModPerms.js';
-import reportToLogs from '../utils/reportToLogs.js';
-import muteMember from '../utils/muteMember.js';
-
-export default {
- data: new SlashCommandBuilder()
- .setName('mute')
- .setDescription('Mute a member.')
- .setDMPermission(false)
- .addUserOption(option =>
- option
- .setName('user')
- .setDescription('The member to mute')
- .setRequired(true)
- )
- .addStringOption(option =>
- option
- .setName('duration')
- .setDescription('The duration of mute')
- .setRequired(true)
- )
- .addStringOption(option =>
- option
- .setName('reason')
- .setDescription('The reason of the mute')
- .setRequired(true)
- ),
- async execute(_, config, interaction) {
- if (!checkForPerms(config, interaction.member)) return interaction.reply({
- epheremal: true,
- content: 'You don\'t have the required permissions.'
- });
-
- await interaction.deferReply();
-
- const user = interaction.options.getUser('user');
-
- const member = await interaction.guild.members.fetch(user);
- const reason = interaction.options.getString('reason');
- const parsedDuration = await muteMember(config, member, {
- duration: interaction.options.getString('duration'),
- reason,
- supportMute: false,
- guild: interaction.guild
- });
-
- reportToLogs(config, interaction.client, 'muted', null, {
- reason,
- actionTo: user,
- actionBy: interaction.member,
- channel: interaction.channel,
- expire: parsedDuration
- }, interaction);
- }
-};
diff --git a/apps/bot-discord/src/commands/trainMessage.js b/apps/bot-discord/src/commands/trainMessage.js
deleted file mode 100644
index 988668d..0000000
--- a/apps/bot-discord/src/commands/trainMessage.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import { ContextMenuCommandBuilder, ApplicationCommandType } from 'discord.js';
-import trainAISelectMenu from '../utils/trainAISelectMenu.js';
-import { checkForPerms } from '../utils/checkSupporterPerms.js'
-
-export default {
- data: new ContextMenuCommandBuilder()
- .setName('Train Message')
- .setType(ApplicationCommandType.Message),
- async execute(helper, config, interaction) {
- if (
- !checkForPerms(config, interaction.member)
- )
- return interaction.reply({
- content: 'You don\'t have the permission to do this.',
- ephemeral: true
- });
-
- trainAISelectMenu(interaction, config, helper);
- }
-};
diff --git a/apps/bot-discord/src/commands/unban.js b/apps/bot-discord/src/commands/unban.js
deleted file mode 100644
index 65e987c..0000000
--- a/apps/bot-discord/src/commands/unban.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import { SlashCommandBuilder } from 'discord.js';
-import { checkForPerms } from '../utils/checkModPerms.js';
-import reportToLogs from '../utils/reportToLogs.js';
-
-export default {
- data: new SlashCommandBuilder()
- .setName('unban')
- .setDescription('Unban a member.')
- .setDMPermission(false)
- .addUserOption(option =>
- option
- .setName('user')
- .setDescription('The member to ban')
- .setRequired(true)
- ),
- async execute(_, config, interaction) {
- if (!checkForPerms(config, interaction.member)) return interaction.reply({
- epheremal: true,
- content: 'You don\'t have the required permissions.'
- });
-
- interaction.guild.members.unban(interaction.options.getUser('user'));
-
- reportToLogs(config, interaction.client, 'unbanned', null, {
- reason: null,
- actionTo: await client.users.fetch(interaction.options.getString('user')),
- actionBy: interaction.member,
- channel: interaction.channel
- }, interaction);
- }
-};
diff --git a/apps/bot-discord/src/commands/unexile.js b/apps/bot-discord/src/commands/unexile.js
deleted file mode 100644
index 023e060..0000000
--- a/apps/bot-discord/src/commands/unexile.js
+++ /dev/null
@@ -1,45 +0,0 @@
-import { SlashCommandBuilder } from 'discord.js';
-import { checkForPerms } from '../utils/checkSupporterPerms.js';
-import reportToLogs from '../utils/reportToLogs.js';
-import unmuteMember from '../utils/unmuteMember.js';
-
-export default {
- data: new SlashCommandBuilder()
- .setName('unexile')
- .setDescription('Get the member back from an exilation.')
- .setDMPermission(false)
- .addUserOption(option =>
- option
- .setName('user')
- .setDescription('The member to unexile')
- .setRequired(true)
- ),
- async execute(_, config, interaction) {
- if (!checkForPerms(config, interaction.member)) return interaction.reply({
- epheremal: true,
- content: 'You don\'t have the required permissions.'
- });
-
- await interaction.deferReply();
-
- const user = interaction.options.getUser('user');
-
- const member = await interaction.guild.members.fetch(user);
- const isExiled = await unmuteMember(config, member, true);
-
- if (!isExiled) {
- await interaction.editReply({
- content: 'Member was not exiled.'
- });
-
- return;
- }
-
- reportToLogs(config, interaction.client, 'unexiled', null, {
- reason: null,
- actionTo: user,
- actionBy: interaction.member,
- channel: interaction.channel,
- }, interaction);
- }
-};
diff --git a/apps/bot-discord/src/commands/unmute.js b/apps/bot-discord/src/commands/unmute.js
deleted file mode 100644
index 7375b14..0000000
--- a/apps/bot-discord/src/commands/unmute.js
+++ /dev/null
@@ -1,45 +0,0 @@
-import { SlashCommandBuilder } from 'discord.js';
-import { checkForPerms } from '../utils/checkModPerms.js';
-import reportToLogs from '../utils/reportToLogs.js';
-import unmuteMember from '../utils/unmuteMember.js';
-
-export default {
- data: new SlashCommandBuilder()
- .setName('unmute')
- .setDescription('Unmute a member.')
- .setDMPermission(false)
- .addUserOption(option =>
- option
- .setName('user')
- .setDescription('The member to unmute')
- .setRequired(true)
- ),
- async execute(_, config, interaction) {
- if (!checkForPerms(config, interaction.member)) return interaction.reply({
- epheremal: true,
- content: 'You don\'t have the required permissions.'
- });
-
- await interaction.deferReply();
-
- const user = interaction.options.getUser('user');
-
- const member = await interaction.guild.members.fetch(user);
- const isMuted = await unmuteMember(config, member, false);
-
- if (!isMuted) {
- await interaction.editReply({
- content: 'Member was not muted.'
- });
-
- return;
- }
-
- reportToLogs(config, interaction.client, 'unmuted', null, {
- reason: null,
- actionTo: user,
- actionBy: interaction.member,
- channel: interaction.channel,
- }, interaction);
- }
-};
diff --git a/apps/bot-discord/src/config.example.json b/apps/bot-discord/src/config.example.json
deleted file mode 100644
index abfc6a5..0000000
--- a/apps/bot-discord/src/config.example.json
+++ /dev/null
@@ -1,358 +0,0 @@
-{
- "discord": {
- "trainRoles": [
- "1019903194941362198",
- "955220417969262612",
- "973886585294704640"
- ],
- "modRoles": [
- "955220417969262612",
- "973886585294704640"
- ],
- "botId": "1038762591805247518",
- "ignoreRole": "1027874293192863765",
- "ignoreChannels": [
- "953965039105232906",
- "953964264400515092",
- "952987428786941952"
- ],
- "supportChannel": "1135563848586379264",
- "mute": {
- "takeRoles": [
- "996121272897519687",
- "965267139902705744",
- "995126555867086938"
- ],
- "giveRoles": [
- "953984696491061289"
- ],
- "supportTakeRoles": [],
- "supportGiveRoles": [
- "1140310515730632814"
- ],
- "supportMuteDuration": 600000
- }
- },
- "logs": {
- "channelId": "952987428786941952",
- "threadId": "1027892160797872179"
- },
- "sticky": {
- "channelId": "1135563848586379264",
- "stickyMessage": {
- "title": "Sticky notice",
- "color": 5150960,
- "fields": [
- {
- "name": "🔸 Before you ask",
- "value": "Check the pinned messages and <#953993848374325269> for existing answers."
- },
- {
- "name": "🔸 How to ask",
- "value": "Include the following information:\n* Version of ReVanced Manager\n* Name of the app you are patching\n* Version of the app you are patching"
- }
- ],
- "footer": {
- "text": "ReVanced",
- "icon_url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- },
- "thumbnail": {
- "url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- }
- },
- "timeout": 180000
- },
- "server": {
- "port": 3000,
- "host": "127.0.0.1"
- },
- "responses": [
- {
- "label": "suggested_version",
- "threshold": 0.85,
- "reply": {
- "title": "Which version is suggested ❓",
- "color": 5150960,
- "fields": [
- {
- "name": "🔸 Regarding your question",
- "value": "The suggested version can be seen in ReVanced Manager in the app selector screen. Refer to the ReVanced Manager documentation in <#953993848374325269> `3`."
- }
- ],
- "footer": {
- "text": "ReVanced",
- "icon_url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- },
- "thumbnail": {
- "url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- }
- }
- },
- {
- "label": "revanced_crash",
- "threshold": 0.85,
- "reply": {
- "title": "Why am I experiencing crashes ❓",
- "color": 5150960,
- "fields": [
- {
- "name": "🔸 Regarding your question",
- "value": "You may have patched an unsuggested version of the app, changed the selection of patches or used a faulty APK. Refer to the documentation in <#953993848374325269> `3` in order to correctly patch your app correctly using ReVanced CLI or ReVanced Manager."
- }
- ],
- "footer": {
- "text": "ReVanced",
- "icon_url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- },
- "thumbnail": {
- "url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- }
- }
- },
- {
- "label": "rvmanager_abort",
- "threshold": 0.85,
- "reply": {
- "title": "Why is ReVanced Manager aborting ❓",
- "color": 5150960,
- "fields": [
- {
- "name": "🔸 Regarding your question",
- "value": "Your device may be unsupported by ReVanced Manager. Refer to the documentation in <#953993848374325269> `3` in order to use ReVanced CLI or check if your device is supported by ReVanced Manager."
- }
- ],
- "footer": {
- "text": "ReVanced",
- "icon_url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- },
- "thumbnail": {
- "url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- }
- }
- },
- {
- "label": "revanced_download",
- "threshold": 0.85,
- "reply": {
- "title": "Where or how to get ReVanced ❓",
- "description": "You might have asked a question that has already been answered in <#953993848374325269>. Make sure to read it as it will answer a lot of your questions, guaranteed.",
- "color": 5150960,
- "fields": [
- {
- "name": "🔸 Regarding your question",
- "value": "You can use ReVanced CLI or ReVanced Manager to get ReVanced. Refer to the documentation in <#953993848374325269> `3`."
- }
- ],
- "footer": {
- "text": "ReVanced",
- "icon_url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- },
- "thumbnail": {
- "url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- }
- }
- },
- {
- "label": "androidtv_support",
- "threshold": 0.85,
- "reply": {
- "title": "Does ReVanced support YouTube for Android TVs ❓",
- "description": "You might have asked a question that has already been answered in <#953993848374325269>. Make sure to read it as it will answer a lot of your questions, guaranteed.",
- "color": 5150960,
- "fields": [
- {
- "name": "🔸 Regarding your question",
- "value": "Please refer to <#953993848374325269> `5`. Alternative, there is [SmartTubeNext](https://github.com/yuliskov/SmartTubeNext#smarttube)."
- }
- ],
- "footer": {
- "text": "ReVanced",
- "icon_url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- },
- "thumbnail": {
- "url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- }
- }
- },
- {
- "label": "revanced_nodownloader",
- "threshold": 0.85,
- "reply": {
- "title": "How do I download videos on YouTube ❓",
- "description": "You might have asked a question that has already been answered in <#953993848374325269>. Make sure to read it as it will answer a lot of your questions, guaranteed.",
- "color": 5150960,
- "fields": [
- {
- "name": "🔸 Regarding your question",
- "value": "In order to be able to download videos on YouTube without YouTube Premium, you can patch YouTube with the `External downloads` patch. You can configure the downloader in the settings of the patched app. NewPipe is the default downloader. Please refer to <#953993848374325269> `24`."
- }
- ],
- "footer": {
- "text": "ReVanced",
- "icon_url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- },
- "thumbnail": {
- "url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- }
- }
- },
- {
- "label": "revanced_casting",
- "threshold": 0.85,
- "reply": {
- "title": "Why can I not cast videos on YouTube ❓",
- "color": 5150960,
- "fields": [
- {
- "name": "🔸 Regarding your question",
- "value": "You may have patched YouTube with the `GmsCore support` patch which makes YouTube use Vanced MicroG instead of Google Services, but Vanced MicroG does not reliably support casting. In order to be able to cast videos on the patched app, you should not patch the app with the `GmsCore support` patch, but then you are forced to mount the patched app with root permissions, because you will not be able to install the app in normal circumstances and Google Services will reject the patched app."
- }
- ],
- "footer": {
- "text": "ReVanced",
- "icon_url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- },
- "thumbnail": {
- "url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- }
- }
- },
- {
- "label": "microg_download",
- "threshold": 0.85,
- "reply": {
- "title": "Where can I get Vanced MicroG ❓",
- "description": "You might have asked a question that has already been answered in <#953993848374325269>. Make sure to read it as it will answer a lot of your questions, guaranteed.",
- "color": 5150960,
- "fields": [
- {
- "name": "🔸 Regarding your question",
- "value": "If you patched YouTube using the `GmsCore support` patch, the patched app will redirect you to the download link of Vanced MicroG if you open it. In case it does not, please refer to <#953993848374325269> `17`."
- }
- ],
- "footer": {
- "text": "ReVanced",
- "icon_url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- },
- "thumbnail": {
- "url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- }
- }
- },
- {
- "label": "microg_nointernet",
- "threshold": 0.85,
- "reply": {
- "title": "Why does YouTube say, I am offline ❓",
- "description": "You might have asked a question that has already been answered in <#953993848374325269>. Make sure to read it as it will answer a lot of your questions, guaranteed.",
- "color": 5150960,
- "fields": [
- {
- "name": "🔸 Regarding your question",
- "value": "Please refer to <#953993848374325269> `15`."
- }
- ],
- "footer": {
- "text": "ReVanced",
- "icon_url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- },
- "thumbnail": {
- "url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- }
- }
- },
- {
- "label": "rvdownload_unofficial",
- "threshold": 0.85,
- "reply": {
- "title": "What are the official links of ReVanced ❓",
- "description": "A list of official links can be found in <#954066838856273960>.",
- "color": 5150960,
- "fields": [
- {
- "name": "🔸 Regarding your question",
- "value": "ReVanced is always available at [revanced.app](https://revanced.app)."
- }
- ],
- "footer": {
- "text": "ReVanced",
- "icon_url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- },
- "thumbnail": {
- "url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- }
- }
- },
- {
- "label": "yt_buffering",
- "threshold": 0.85,
- "reply": {
- "title": "Why do videos fail to play❓",
- "description": "You might have asked a question that has been answered in the <#953993848374325269> channel already. Make sure to read it as it will answer a lot of your questions, guaranteed.",
- "color": 5150960,
- "fields": [
- {
- "name": "🔸 Regarding your question",
- "value": "Please refer to <#953993848374325269> `32`."
- }
- ],
- "footer": {
- "text": "ReVanced",
- "icon_url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- },
- "thumbnail": {
- "url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- }
- }
- },
- {
- "label": "false",
- "threshold": 0,
- "reply": null
- }
- ],
- "ocrResponses": [
- {
- "regex": "is not installed",
- "reply": {
- "title": "How do I download videos on YouTube ❓",
- "description": "You might have asked a question that has already been answered in <#953993848374325269>. Make sure to read it as it will answer a lot of your questions, guaranteed.",
- "color": 5150960,
- "fields": [
- {
- "name": "🔸 Regarding your question",
- "value": "In order to be able to download videos on YouTube without YouTube Premium, you can patch YouTube with the `External downloads` patch. You can configure the downloader in the settings of the patched app. NewPipe is the default downloader. Please refer to <#953993848374325269> `24`."
- }
- ],
- "footer": {
- "text": "ReVanced",
- "icon_url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- },
- "thumbnail": {
- "url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- }
- }
- },
- {
- "regex": "You're offline|Please check your",
- "reply": {
- "title": "Why does YouTube say, I am offline ❓",
- "description": "You might have asked a question that has already been answered in <#953993848374325269>. Make sure to read it as it will answer a lot of your questions, guaranteed.",
- "color": 5150960,
- "fields": [
- {
- "name": "🔸 Regarding your question",
- "value": "Please refer to <#953993848374325269> `15`."
- }
- ],
- "footer": {
- "text": "ReVanced",
- "icon_url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- },
- "thumbnail": {
- "url": "https://cdn.discordapp.com/attachments/1095487869923119144/1115436493050224660/revanced-logo.png"
- }
- }
- }
- ]
-}
diff --git a/apps/bot-discord/src/events/guildMemberAdd.js b/apps/bot-discord/src/events/guildMemberAdd.js
deleted file mode 100644
index d3294cb..0000000
--- a/apps/bot-discord/src/events/guildMemberAdd.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import { Events } from 'discord.js';
-import cureUsername from '../utils/cureUsername.js';
-
-export default {
- name: Events.GuildMemberAdd,
- once: false,
- async execute(_, config, member) {
- cureUsername(member);
- const mute = await client.db.collection('muted').findOne({
- guild_id: member.guild.id,
- user_id: member.id
- });
-
- if (mute) {
- // Add the roles given.
- member.roles.add(mute.support_mute ?
- config.mute.supportGiveRoles :
- config.mute.giveRoles
- );
- }
- }
-};
diff --git a/apps/bot-discord/src/events/guildMemberUpdate.js b/apps/bot-discord/src/events/guildMemberUpdate.js
deleted file mode 100644
index b34429d..0000000
--- a/apps/bot-discord/src/events/guildMemberUpdate.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import { Events } from 'discord.js';
-import cureUsername from '../utils/cureUsername.js';
-
-export default {
- name: Events.GuildMemberUpdate,
- once: false,
- async execute(_, config, oldMember, newMember) {
- cureUsername(newMember);
- }
-};
diff --git a/apps/bot-discord/src/events/interactionCreate.js b/apps/bot-discord/src/events/interactionCreate.js
deleted file mode 100644
index 6cf9477..0000000
--- a/apps/bot-discord/src/events/interactionCreate.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import { Events } from 'discord.js';
-
-export default {
- name: Events.InteractionCreate,
- once: false,
- async execute(helper, config, interaction) {
- const command = interaction.client.commands.get(interaction.commandName || interaction.customId);
-
- // It's the select menu interaction (hopefully), ignore.
- if (!command) return;
-
- try {
- await command.execute(helper, config, interaction);
- } catch (error) {
- console.error(error);
- await interaction.reply({
- content: 'There was an error while executing this command!',
- ephemeral: true
- });
- }
- }
-};
diff --git a/apps/bot-discord/src/events/messageCreate.js b/apps/bot-discord/src/events/messageCreate.js
deleted file mode 100644
index da59826..0000000
--- a/apps/bot-discord/src/events/messageCreate.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import { Events } from 'discord.js';
-
-export default {
- name: Events.MessageCreate,
- once: false,
- async execute(helper, config, msg) {
- if (!msg.guild || msg.system || msg.webhookId || msg.author.bot) return;
- if (msg.content.startsWith('?')) {
- const [cmd, args] = msg.content.replace('?', '').split(/\s/g);
- const command = msg.client.msgCommands.get(cmd);
- if (command) {
- await command.execute(msg, args, config);
- }
- }
- const hasImmunity = msg.member.roles.cache.some(role => role.id === config.discord.ignoreRole);
- if (config.discord.ignoreChannels.includes(msg.channelId)) return;
- if (msg.attachments.first()?.contentType?.startsWith('image') && !hasImmunity) {
- helper.scanImage(msg.attachments.first().url, `${msg.channelId}/${msg.id}`);
- }
-
- if (msg.content && !hasImmunity) {
- helper.scanText(
- msg.content.toLowerCase().replace(/<.*?>/g, ''),
- `${msg.channelId}/${msg.id}`
- );
- }
-
- // Sticky message
- if (msg.channel.id !== config.sticky.channelId) return;
- if (msg.client.stickiedMessageTimeout) clearInterval(msg.client.stickiedMessageTimeout);
-
- msg.client.stickiedMessageTimeout = setTimeout(async () => {
- const channel = await msg.client.channels.fetch(config.sticky.channelId);
-
- const message = await channel.send({ embeds: [config.sticky.stickyMessage] });
-
- if (msg.client.stickiedMessage && channel.messages.cache.get(msg.client.stickiedMessage)?.deletable)
- channel.messages.delete(msg.client.stickiedMessage).catch(() => {});
-
- msg.client.stickiedMessage = message.id;
- }, config.sticky.timeout);
- }
-};
diff --git a/apps/bot-discord/src/events/ready.js b/apps/bot-discord/src/events/ready.js
deleted file mode 100644
index dd7337e..0000000
--- a/apps/bot-discord/src/events/ready.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import { Events } from 'discord.js';
-import setMuteTimeout from '../utils/setMuteTimeout.js';
-
-export default {
- name: Events.ClientReady,
- once: false,
- async execute(_, config, client) {
- console.log('Client is ready. Reloading mutes.');
-
- const mutes = await client.db.collection('muted').find().toArray();
-
- for (const mute of mutes) {
- await setMuteTimeout(mute, client, config);
- }
-
- console.log(`Loaded ${mutes.length} mutes.`);
- }
-};
diff --git a/apps/bot-discord/src/events/threadCreate.js b/apps/bot-discord/src/events/threadCreate.js
deleted file mode 100644
index d242e65..0000000
--- a/apps/bot-discord/src/events/threadCreate.js
+++ /dev/null
@@ -1,9 +0,0 @@
-import { Events } from 'discord.js';
-
-export default {
- name: Events.ThreadCreate,
- once: false,
- async execute(helper, _, thread) {
- helper.scanText(thread.name.toLowerCase(), thread.id);
- }
-};
diff --git a/apps/bot-discord/src/helperEvents/aiResponse.js b/apps/bot-discord/src/helperEvents/aiResponse.js
deleted file mode 100644
index b54027a..0000000
--- a/apps/bot-discord/src/helperEvents/aiResponse.js
+++ /dev/null
@@ -1,97 +0,0 @@
-import {
- EmbedBuilder,
- ActionRowBuilder,
- ButtonBuilder,
- ButtonStyle
-} from 'discord.js';
-
-export default {
- name: 'aiResponse',
- once: false,
- async execute(client, config, helper, aiRes) {
- if (!aiRes.response) return;
- if (!aiRes.response[0]) return;
-
- try {
- const ids = aiRes.id.split('/');
-
- const intent = aiRes.response.reduce((a, b) =>
- a.confidence > b.confidence ? a : b
- );
-
- const response = config.responses.find(
- (res) => res.label === intent.name
- );
-
- if (response.threshold > intent.confidence) return;
- if (!response.reply) return;
-
- const embed = response.reply;
- const feedbackRow = new ActionRowBuilder().addComponents(
- new ButtonBuilder()
- .setCustomId('fb-like')
- .setEmoji('👍')
- .setStyle(ButtonStyle.Primary),
- new ButtonBuilder()
- .setCustomId('fb-dislike')
- .setEmoji('👎')
- .setStyle(ButtonStyle.Primary)
- );
-
- let channel = client.channels.cache.get(ids[0]);
-
- if (!channel) {
- await client.channels.fetch(ids[0]);
- channel = client.channels.cache.get(ids[0]);
- }
-
- if (!ids[1]) {
- // This means that it's a thread/forum.
- const threadEditOption = { locked: false, archived: false };
- if (response.closeThread) {
- threadEditOption.archived = true;
- }
-
- if (response.lockThread) {
- threadEditOption.locked = true;
- }
-
- await channel.send({
- embeds: [embed],
- components: [feedbackRow]
- });
-
- channel.edit(threadEditOption);
- } else {
- let message = channel.messages.cache.get(ids[1]);
-
- if (!message) {
- await channel.messages.fetch(ids[1]);
- message = channel.messages.cache.get(ids[1]);
- }
-
- const firstMsg = (await channel.messages.fetch()).first();
-
- await message.reply({
- embeds: [embed],
- components: [feedbackRow]
- });
-
- if (firstMsg == message) {
- const threadEditOption = { locked: false, archived: false };
- if (response.closeThread) {
- threadEditOption.archived = true;
- }
-
- if (response.lockThread) {
- threadEditOption.locked = true;
- }
-
- channel.edit(threadEditOption);
- }
- }
- } catch (e) {
- console.log(e);
- }
- }
-};
diff --git a/apps/bot-discord/src/helperEvents/ocrResponse.js b/apps/bot-discord/src/helperEvents/ocrResponse.js
deleted file mode 100644
index 2d05814..0000000
--- a/apps/bot-discord/src/helperEvents/ocrResponse.js
+++ /dev/null
@@ -1,31 +0,0 @@
-export default {
- name: 'ocrResponse',
- once: false,
- async execute(client, config, helper, ocrRes) {
- try {
- const ids = ocrRes.id.split('/');
- let channel = client.channels.cache.get(ids[0]);
-
- if (!channel) {
- await client.channels.fetch(ids[0]);
- channel = client.channels.cache.get(ids[0]);
- }
-
- let message = channel.messages.cache.get(ids[1]);
-
- if (!message) {
- await channel.messages.fetch(ids[1]);
- message = channel.messages.cache.get(ids[1]);
- }
-
- for (const ocrReply of config.ocrResponses) {
- if (ocrRes.ocrText.match(ocrReply.regex)) {
- message.reply({ embeds: [ocrReply.reply] });
- break;
- }
- }
- } catch (e) {
- console.log(e);
- }
- }
-};
diff --git a/apps/bot-discord/src/index.js b/apps/bot-discord/src/index.js
deleted file mode 100644
index 11652cc..0000000
--- a/apps/bot-discord/src/index.js
+++ /dev/null
@@ -1,108 +0,0 @@
-import { Client, GatewayIntentBits, Collection } from 'discord.js';
-import { readFileSync, readdirSync } from 'node:fs';
-// Fix __dirname not being defined in ES modules. (https://stackoverflow.com/a/64383997)
-import { fileURLToPath } from 'node:url';
-import { dirname, join } from 'node:path';
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = dirname(__filename);
-import HelperClient from '@revanced-helper/helper-client';
-import config from './config.json' assert { type: 'json' };
-import { MongoClient } from 'mongodb';
-const helper = new HelperClient(config);
-const mongoDBClient = new MongoClient(process.env.MONGODB_URI);
-
-await mongoDBClient.connect();
-helper.connect();
-
-
-const client = new Client({
- intents: [
- GatewayIntentBits.Guilds,
- GatewayIntentBits.GuildMessages,
- GatewayIntentBits.MessageContent
- ]
-});
-
-client.commands = new Collection();
-client.msgCommands = new Collection();
-client.trainingVotes = new Collection();
-client.stickiedMessage = null;
-client.stickiedMessageTimeout = null;
-client.db = mongoDBClient.db('revanced_discord_bot');
-client.mutes = new Collection();
-
-const commandsPath = join(__dirname, 'commands');
-const commandFiles = readdirSync(commandsPath).filter((file) =>
- file.endsWith('.js')
-);
-
-for (const file of commandFiles) {
- const filePath = join(commandsPath, file);
- const command = (await import(`file://${filePath}`)).default;
- if ('data' in command && 'execute' in command) {
- client.commands.set(command.data.name, command);
- } else {
- console.log(
- `[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.`
- );
- }
-}
-
-const msgCommandsPath = join(__dirname, 'msgCommands');
-const msgCommandFiles = readdirSync(msgCommandsPath).filter((file) =>
- file.endsWith('.js')
-);
-
-for (const file of msgCommandFiles) {
- const filePath = join(msgCommandsPath, file);
- const command = (await import(`file://${filePath}`)).default;
- if ('name' in command && 'execute' in command) {
- client.msgCommands.set(command.name, command);
- } else {
- console.log(
- `[WARNING] The command at ${filePath} is missing a required "name" or "execute" property.`
- );
- }
-}
-
-const discordEventsPath = join(__dirname, 'events');
-const discordEventFiles = readdirSync(discordEventsPath).filter((file) =>
- file.endsWith('.js')
-);
-
-for (const file of discordEventFiles) {
- const filePath = join(discordEventsPath, file);
- const event = (await import(`file://${filePath}`)).default;
- if (event.once) {
- client.once(event.name, (...args) =>
- event.execute(helper, config, ...args)
- );
- } else {
- client.on(event.name, (...args) =>
- event.execute(helper, config, ...args)
- );
- }
-}
-
-// The ReVanced Helper events.
-
-const helperEventsPath = join(__dirname, 'helperEvents');
-const helperEventFiles = readdirSync(helperEventsPath).filter((file) =>
- file.endsWith('.js')
-);
-
-for (const file of helperEventFiles) {
- const filePath = join(helperEventsPath, file);
- const event = (await import(`file://${filePath}`)).default;
- if (event.once) {
- helper.once(event.name, (...args) =>
- event.execute(client, config, helper, ...args)
- );
- } else {
- helper.on(event.name, (...args) =>
- event.execute(client, config, helper, ...args)
- );
- }
-}
-
-client.login(process.env.DISCORD_TOKEN);
\ No newline at end of file
diff --git a/apps/bot-discord/src/msgCommands/exile.js b/apps/bot-discord/src/msgCommands/exile.js
deleted file mode 100644
index 3939110..0000000
--- a/apps/bot-discord/src/msgCommands/exile.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import exileMemberToChannel from '../utils/exileMemberToChannel.js';
-import { checkForPerms } from '../utils/checkSupporterPerms.js'
-import muteMember from '../utils/muteMember.js';
-import reportToLogs from '../utils/reportToLogs.js';
-
-export default {
- name: 'exile',
- async execute(msg, args, config) {
- if (!checkForPerms(config, msg.member)) return msg.reply('You don\'t have the permission to do this.');
-
- if (!msg.reference) return msg.reply('You did not reply to anyone!');
- const referencedMsg = await msg.channel.messages.fetch(msg.reference.messageId);
- let message = referencedMsg.content;
- if (args && args[0]) {
- if (isNaN(args[0])) return msg.reply('The argument you entered is not a number!');
-
- const msgsByAuthor = (await msg.channel.messages.fetch({ limit: 50 })).filter(
- m => m.author.id === referencedMsg.author.id
- ).map(m => m.content);
- message = msgsByAuthor.slice(Number(`-${args[0]}`));
- }
-
- const parsedDuration = await muteMember(config, referencedMsg.member, {
- supportMute: true,
- guild: msg.guild
- });
-
- exileMemberToChannel(referencedMsg.author, msg.channel, message, null, config, false);
-
- reportToLogs(config, msg.client, 'exiled', null, {
- reason: null,
- actionTo: referencedMsg.author,
- actionBy: msg.member,
- channel: msg.channel,
- expire: parsedDuration
- }, null, msg);
-
- await referencedMsg.delete();
- }
-}
\ No newline at end of file
diff --git a/apps/bot-discord/src/package-lock.json b/apps/bot-discord/src/package-lock.json
deleted file mode 100644
index f6bcfef..0000000
--- a/apps/bot-discord/src/package-lock.json
+++ /dev/null
@@ -1,1335 +0,0 @@
-{
- "name": "bot-discord",
- "version": "1.0.0",
- "lockfileVersion": 2,
- "requires": true,
- "packages": {
- "": {
- "name": "bot-discord",
- "version": "1.0.0",
- "license": "GPL-3.0-or-later",
- "dependencies": {
- "@revanced-helper/helper-client": "file:../../../packages/client",
- "decancer": "^1.6.5",
- "discord.js": "^14.11.0",
- "mongodb": "^5.7.0",
- "parse-duration": "^1.1.0"
- }
- },
- "node_modules/@discordjs/builders": {
- "version": "1.6.3",
- "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.6.3.tgz",
- "integrity": "sha512-CTCh8NqED3iecTNuiz49mwSsrc2iQb4d0MjMdmS/8pb69Y4IlzJ/DIy/p5GFlgOrFbNO2WzMHkWKQSiJ3VNXaw==",
- "dependencies": {
- "@discordjs/formatters": "^0.3.1",
- "@discordjs/util": "^0.3.1",
- "@sapphire/shapeshift": "^3.8.2",
- "discord-api-types": "^0.37.41",
- "fast-deep-equal": "^3.1.3",
- "ts-mixer": "^6.0.3",
- "tslib": "^2.5.0"
- },
- "engines": {
- "node": ">=16.9.0"
- }
- },
- "node_modules/@discordjs/collection": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.1.tgz",
- "integrity": "sha512-aWEc9DCf3TMDe9iaJoOnO2+JVAjeRNuRxPZQA6GVvBf+Z3gqUuWYBy2NWh4+5CLYq5uoc3MOvUQ5H5m8CJBqOA==",
- "engines": {
- "node": ">=16.9.0"
- }
- },
- "node_modules/@discordjs/formatters": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.3.1.tgz",
- "integrity": "sha512-M7X4IGiSeh4znwcRGcs+49B5tBkNDn4k5bmhxJDAUhRxRHTiFAOTVUNQ6yAKySu5jZTnCbSvTYHW3w0rAzV1MA==",
- "dependencies": {
- "discord-api-types": "^0.37.41"
- },
- "engines": {
- "node": ">=16.9.0"
- }
- },
- "node_modules/@discordjs/rest": {
- "version": "1.7.1",
- "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-1.7.1.tgz",
- "integrity": "sha512-Ofa9UqT0U45G/eX86cURQnX7gzOJLG2oC28VhIk/G6IliYgQF7jFByBJEykPSHE4MxPhqCleYvmsrtfKh1nYmQ==",
- "dependencies": {
- "@discordjs/collection": "^1.5.1",
- "@discordjs/util": "^0.3.0",
- "@sapphire/async-queue": "^1.5.0",
- "@sapphire/snowflake": "^3.4.2",
- "discord-api-types": "^0.37.41",
- "file-type": "^18.3.0",
- "tslib": "^2.5.0",
- "undici": "^5.22.0"
- },
- "engines": {
- "node": ">=16.9.0"
- }
- },
- "node_modules/@discordjs/util": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-0.3.1.tgz",
- "integrity": "sha512-HxXKYKg7vohx2/OupUN/4Sd02Ev3PBJ5q0gtjdcvXb0ErCva8jNHWfe/v5sU3UKjIB/uxOhc+TDOnhqffj9pRA==",
- "engines": {
- "node": ">=16.9.0"
- }
- },
- "node_modules/@discordjs/ws": {
- "version": "0.8.3",
- "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-0.8.3.tgz",
- "integrity": "sha512-hcYtppanjHecbdNyCKQNH2I4RP9UrphDgmRgLYrATEQF1oo4sYSve7ZmGsBEXSzH72MO2tBPdWSThunbxUVk0g==",
- "dependencies": {
- "@discordjs/collection": "^1.5.1",
- "@discordjs/rest": "^1.7.1",
- "@discordjs/util": "^0.3.1",
- "@sapphire/async-queue": "^1.5.0",
- "@types/ws": "^8.5.4",
- "@vladfrangu/async_event_emitter": "^2.2.1",
- "discord-api-types": "^0.37.41",
- "tslib": "^2.5.0",
- "ws": "^8.13.0"
- },
- "engines": {
- "node": ">=16.9.0"
- }
- },
- "node_modules/@mongodb-js/saslprep": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.0.tgz",
- "integrity": "sha512-Xfijy7HvfzzqiOAhAepF4SGN5e9leLkMvg/OPOF97XemjfVCYN/oWa75wnkc6mltMSTwY+XlbhWgUOJmkFspSw==",
- "optional": true,
- "dependencies": {
- "sparse-bitfield": "^3.0.3"
- }
- },
- "node_modules/@revanced-helper/helper-client": {
- "version": "1.0.0",
- "resolved": "file:../../../packages/client",
- "license": "GPL-3.0-or-later",
- "dependencies": {
- "bson": "^4.7.0"
- }
- },
- "node_modules/@revanced-helper/helper-client/node_modules/bson": {
- "version": "4.7.2",
- "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.2.tgz",
- "integrity": "sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ==",
- "dependencies": {
- "buffer": "^5.6.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@sapphire/async-queue": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz",
- "integrity": "sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==",
- "engines": {
- "node": ">=v14.0.0",
- "npm": ">=7.0.0"
- }
- },
- "node_modules/@sapphire/shapeshift": {
- "version": "3.9.2",
- "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.2.tgz",
- "integrity": "sha512-YRbCXWy969oGIdqR/wha62eX8GNHsvyYi0Rfd4rNW6tSVVa8p0ELiMEuOH/k8rgtvRoM+EMV7Csqz77YdwiDpA==",
- "dependencies": {
- "fast-deep-equal": "^3.1.3",
- "lodash": "^4.17.21"
- },
- "engines": {
- "node": ">=v14.0.0",
- "npm": ">=7.0.0"
- }
- },
- "node_modules/@sapphire/snowflake": {
- "version": "3.5.1",
- "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.1.tgz",
- "integrity": "sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA==",
- "engines": {
- "node": ">=v14.0.0",
- "npm": ">=7.0.0"
- }
- },
- "node_modules/@tokenizer/token": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz",
- "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="
- },
- "node_modules/@types/node": {
- "version": "20.2.5",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.5.tgz",
- "integrity": "sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ=="
- },
- "node_modules/@types/webidl-conversions": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
- "integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog=="
- },
- "node_modules/@types/whatwg-url": {
- "version": "8.2.2",
- "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz",
- "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==",
- "dependencies": {
- "@types/node": "*",
- "@types/webidl-conversions": "*"
- }
- },
- "node_modules/@types/ws": {
- "version": "8.5.4",
- "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz",
- "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==",
- "dependencies": {
- "@types/node": "*"
- }
- },
- "node_modules/@vierofernando/decancer-android-arm-eabi": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/@vierofernando/decancer-android-arm-eabi/-/decancer-android-arm-eabi-1.6.5.tgz",
- "integrity": "sha512-/xPMebqSFb6fePZdwD9Pz8pIc9GkCGlMOQA4ucFtKeepQrMhoil4qN+ri5DUSeW9PFvnj/cEWuPEeNDbFc4WyA==",
- "cpu": [
- "arm"
- ],
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@vierofernando/decancer-android-arm64": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/@vierofernando/decancer-android-arm64/-/decancer-android-arm64-1.6.5.tgz",
- "integrity": "sha512-FraWlT6lfjFuV5L383+XzzFD5I2pzZ5TRDfix4BVXvDxjnO8ZKt4AB7DbWteDVu18zZbuVpBh3Tp1Eu1adidUg==",
- "cpu": [
- "arm64"
- ],
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@vierofernando/decancer-darwin-arm64": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/@vierofernando/decancer-darwin-arm64/-/decancer-darwin-arm64-1.6.5.tgz",
- "integrity": "sha512-pOarySDUPdxf/YQ673HxH+tJubapiiPt7SOuK8lRw3NoiQZ3cOf/LofU8rEUgK/yKfDyWbmQLnvMi1Hl1JTmhg==",
- "cpu": [
- "arm64"
- ],
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@vierofernando/decancer-darwin-x64": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/@vierofernando/decancer-darwin-x64/-/decancer-darwin-x64-1.6.5.tgz",
- "integrity": "sha512-B7JzUC5EHQtA7yJOrdRrKjHWBbzvBaPNAKHBKJ+brAwqa3yStpBodJZTgsfGHidCY8Gje0pGxSZVbPnGs+5Xbg==",
- "cpu": [
- "x64"
- ],
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@vierofernando/decancer-linux-arm-gnueabihf": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/@vierofernando/decancer-linux-arm-gnueabihf/-/decancer-linux-arm-gnueabihf-1.6.5.tgz",
- "integrity": "sha512-1ALPTMzUo750lIuHn/paZ2wq+GkDXv15dP9w4bmP3ytrYVj8b0uJmb57FexNEIMPf4M0gkGmyNLjq+Y1AJoQvw==",
- "cpu": [
- "arm"
- ],
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@vierofernando/decancer-linux-arm64-gnu": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/@vierofernando/decancer-linux-arm64-gnu/-/decancer-linux-arm64-gnu-1.6.5.tgz",
- "integrity": "sha512-RDNTJ9812zlQkWRxZS513xZoSUeRbONzcFX6VDnl/Lx20NVRZOryF8o4EtKDwzEd3kQrIr2tQlZyLLLsTGL48g==",
- "cpu": [
- "arm64"
- ],
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@vierofernando/decancer-linux-arm64-musl": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/@vierofernando/decancer-linux-arm64-musl/-/decancer-linux-arm64-musl-1.6.5.tgz",
- "integrity": "sha512-Qnm6yQxvUF8uojyIIUiZepTZIyJN2jdqvm2QptxfB1LGABkWCpTlv+xml8KTPFTUcPT1Epwye1FaVEwd90W7VQ==",
- "cpu": [
- "arm64"
- ],
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@vierofernando/decancer-linux-x64-gnu": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/@vierofernando/decancer-linux-x64-gnu/-/decancer-linux-x64-gnu-1.6.5.tgz",
- "integrity": "sha512-eKdF0jsdVpm+lcDHALqtH79Z8vPX5qsoJHM2YHrQ5pJ3khP2+OcEYdAyis2rl438OK6NJyQZfECSUSj9dtfAeQ==",
- "cpu": [
- "x64"
- ],
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@vierofernando/decancer-linux-x64-musl": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/@vierofernando/decancer-linux-x64-musl/-/decancer-linux-x64-musl-1.6.5.tgz",
- "integrity": "sha512-RaJoJSIkLSu0l4tODVFWoeE+4BSVjHUn+Gb3yQKn5DHmsl1/EOuj6rlwX6uddleV9aQIDEAljSL3SExNZbmm2A==",
- "cpu": [
- "x64"
- ],
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@vierofernando/decancer-win32-arm64-msvc": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/@vierofernando/decancer-win32-arm64-msvc/-/decancer-win32-arm64-msvc-1.6.5.tgz",
- "integrity": "sha512-SXI6r8m+J4vYCvjKQeafukSpBORU9wzM38SkBhjdp8wfcHVYfjVtoHVr4JxkpNfMJoIhv9j2MJYIaYVExvw8pg==",
- "cpu": [
- "arm64"
- ],
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@vierofernando/decancer-win32-ia32-msvc": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/@vierofernando/decancer-win32-ia32-msvc/-/decancer-win32-ia32-msvc-1.6.5.tgz",
- "integrity": "sha512-Ml6Gx6iwOzLopcH8BEd3Kn2MQ1bg5S4mKHQrxNn2MK3SqCLNzZKZhoWe18aCzaKLnwTTkcZvXNcZk1OLPLxmUw==",
- "cpu": [
- "ia32"
- ],
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@vierofernando/decancer-win32-x64-msvc": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/@vierofernando/decancer-win32-x64-msvc/-/decancer-win32-x64-msvc-1.6.5.tgz",
- "integrity": "sha512-fnMKkLkYJ/K/e1jo6WfwpoI4eNEkcWsA/rJMMF6XGLD6YhHnZZdlugqsbSK8j4GiBBTfgj6yCeCMEfLe2QP15w==",
- "cpu": [
- "x64"
- ],
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@vladfrangu/async_event_emitter": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.2.tgz",
- "integrity": "sha512-HIzRG7sy88UZjBJamssEczH5q7t5+axva19UbZLO6u0ySbYPrwzWiXBcC0WuHyhKKoeCyneH+FvYzKQq/zTtkQ==",
- "engines": {
- "node": ">=v14.0.0",
- "npm": ">=7.0.0"
- }
- },
- "node_modules/base64-js": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
- "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ]
- },
- "node_modules/bson": {
- "version": "5.4.0",
- "resolved": "https://registry.npmjs.org/bson/-/bson-5.4.0.tgz",
- "integrity": "sha512-WRZ5SQI5GfUuKnPTNmAYPiKIof3ORXAF4IRU5UcgmivNIon01rWQlw5RUH954dpu8yGL8T59YShVddIPaU/gFA==",
- "engines": {
- "node": ">=14.20.1"
- }
- },
- "node_modules/buffer": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
- "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "dependencies": {
- "base64-js": "^1.3.1",
- "ieee754": "^1.1.13"
- }
- },
- "node_modules/busboy": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
- "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
- "dependencies": {
- "streamsearch": "^1.1.0"
- },
- "engines": {
- "node": ">=10.16.0"
- }
- },
- "node_modules/decancer": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/decancer/-/decancer-1.6.5.tgz",
- "integrity": "sha512-7p9ShXWXwKwTIwa5VoFtvUpIWMI4MEgCYLJqOwczBDyEHR65GhTxW/l0V/fazxV3w9KvlmoHI0HtTTI3nSNy1A==",
- "engines": {
- "node": ">= 16"
- },
- "optionalDependencies": {
- "@vierofernando/decancer-android-arm-eabi": "1.6.5",
- "@vierofernando/decancer-android-arm64": "1.6.5",
- "@vierofernando/decancer-darwin-arm64": "1.6.5",
- "@vierofernando/decancer-darwin-x64": "1.6.5",
- "@vierofernando/decancer-linux-arm-gnueabihf": "1.6.5",
- "@vierofernando/decancer-linux-arm64-gnu": "1.6.5",
- "@vierofernando/decancer-linux-arm64-musl": "1.6.5",
- "@vierofernando/decancer-linux-x64-gnu": "1.6.5",
- "@vierofernando/decancer-linux-x64-musl": "1.6.5",
- "@vierofernando/decancer-win32-arm64-msvc": "1.6.5",
- "@vierofernando/decancer-win32-ia32-msvc": "1.6.5",
- "@vierofernando/decancer-win32-x64-msvc": "1.6.5"
- }
- },
- "node_modules/discord-api-types": {
- "version": "0.37.43",
- "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.43.tgz",
- "integrity": "sha512-bBhDWU3TF9KADxR/mHp1K4Bvu/LRtFQdGyBjADu4e66F3ZnD4kp12W/SJCttIaCcMXzPV3sfty6eDGRNRph51Q=="
- },
- "node_modules/discord.js": {
- "version": "14.11.0",
- "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.11.0.tgz",
- "integrity": "sha512-CkueWYFQ28U38YPR8HgsBR/QT35oPpMbEsTNM30Fs8loBIhnA4s70AwQEoy6JvLcpWWJO7GY0y2BUzZmuBMepQ==",
- "dependencies": {
- "@discordjs/builders": "^1.6.3",
- "@discordjs/collection": "^1.5.1",
- "@discordjs/formatters": "^0.3.1",
- "@discordjs/rest": "^1.7.1",
- "@discordjs/util": "^0.3.1",
- "@discordjs/ws": "^0.8.3",
- "@sapphire/snowflake": "^3.4.2",
- "@types/ws": "^8.5.4",
- "discord-api-types": "^0.37.41",
- "fast-deep-equal": "^3.1.3",
- "lodash.snakecase": "^4.1.1",
- "tslib": "^2.5.0",
- "undici": "^5.22.0",
- "ws": "^8.13.0"
- },
- "engines": {
- "node": ">=16.9.0"
- }
- },
- "node_modules/fast-deep-equal": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
- },
- "node_modules/file-type": {
- "version": "18.5.0",
- "resolved": "https://registry.npmjs.org/file-type/-/file-type-18.5.0.tgz",
- "integrity": "sha512-yvpl5U868+V6PqXHMmsESpg6unQ5GfnPssl4dxdJudBrr9qy7Fddt7EVX1VLlddFfe8Gj9N7goCZH22FXuSQXQ==",
- "dependencies": {
- "readable-web-to-node-stream": "^3.0.2",
- "strtok3": "^7.0.0",
- "token-types": "^5.0.1"
- },
- "engines": {
- "node": ">=14.16"
- },
- "funding": {
- "url": "https://github.com/sindresorhus/file-type?sponsor=1"
- }
- },
- "node_modules/ieee754": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
- "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ]
- },
- "node_modules/inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
- },
- "node_modules/ip": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz",
- "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ=="
- },
- "node_modules/lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
- },
- "node_modules/lodash.snakecase": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz",
- "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw=="
- },
- "node_modules/memory-pager": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
- "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
- "optional": true
- },
- "node_modules/mongodb": {
- "version": "5.8.1",
- "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.8.1.tgz",
- "integrity": "sha512-wKyh4kZvm6NrCPH8AxyzXm3JBoEf4Xulo0aUWh3hCgwgYJxyQ1KLST86ZZaSWdj6/kxYUA3+YZuyADCE61CMSg==",
- "dependencies": {
- "bson": "^5.4.0",
- "mongodb-connection-string-url": "^2.6.0",
- "socks": "^2.7.1"
- },
- "engines": {
- "node": ">=14.20.1"
- },
- "optionalDependencies": {
- "@mongodb-js/saslprep": "^1.1.0"
- },
- "peerDependencies": {
- "@aws-sdk/credential-providers": "^3.188.0",
- "@mongodb-js/zstd": "^1.0.0",
- "kerberos": "^1.0.0 || ^2.0.0",
- "mongodb-client-encryption": ">=2.3.0 <3",
- "snappy": "^7.2.2"
- },
- "peerDependenciesMeta": {
- "@aws-sdk/credential-providers": {
- "optional": true
- },
- "@mongodb-js/zstd": {
- "optional": true
- },
- "kerberos": {
- "optional": true
- },
- "mongodb-client-encryption": {
- "optional": true
- },
- "snappy": {
- "optional": true
- }
- }
- },
- "node_modules/mongodb-connection-string-url": {
- "version": "2.6.0",
- "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz",
- "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==",
- "dependencies": {
- "@types/whatwg-url": "^8.2.1",
- "whatwg-url": "^11.0.0"
- }
- },
- "node_modules/parse-duration": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/parse-duration/-/parse-duration-1.1.0.tgz",
- "integrity": "sha512-z6t9dvSJYaPoQq7quMzdEagSFtpGu+utzHqqxmpVWNNZRIXnvqyCvn9XsTdh7c/w0Bqmdz3RB3YnRaKtpRtEXQ=="
- },
- "node_modules/peek-readable": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz",
- "integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==",
- "engines": {
- "node": ">=14.16"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/Borewit"
- }
- },
- "node_modules/punycode": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
- "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/readable-stream": {
- "version": "3.6.2",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
- "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
- "dependencies": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/readable-web-to-node-stream": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz",
- "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==",
- "dependencies": {
- "readable-stream": "^3.6.0"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/Borewit"
- }
- },
- "node_modules/safe-buffer": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ]
- },
- "node_modules/smart-buffer": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
- "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
- "engines": {
- "node": ">= 6.0.0",
- "npm": ">= 3.0.0"
- }
- },
- "node_modules/socks": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz",
- "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==",
- "dependencies": {
- "ip": "^2.0.0",
- "smart-buffer": "^4.2.0"
- },
- "engines": {
- "node": ">= 10.13.0",
- "npm": ">= 3.0.0"
- }
- },
- "node_modules/sparse-bitfield": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
- "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
- "optional": true,
- "dependencies": {
- "memory-pager": "^1.0.2"
- }
- },
- "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_decoder": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
- "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
- "dependencies": {
- "safe-buffer": "~5.2.0"
- }
- },
- "node_modules/strtok3": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz",
- "integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==",
- "dependencies": {
- "@tokenizer/token": "^0.3.0",
- "peek-readable": "^5.0.0"
- },
- "engines": {
- "node": ">=14.16"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/Borewit"
- }
- },
- "node_modules/token-types": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz",
- "integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==",
- "dependencies": {
- "@tokenizer/token": "^0.3.0",
- "ieee754": "^1.2.1"
- },
- "engines": {
- "node": ">=14.16"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/Borewit"
- }
- },
- "node_modules/tr46": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz",
- "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==",
- "dependencies": {
- "punycode": "^2.1.1"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/ts-mixer": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz",
- "integrity": "sha512-k43M7uCG1AkTyxgnmI5MPwKoUvS/bRvLvUb7+Pgpdlmok8AoqmUaZxUUw8zKM5B1lqZrt41GjYgnvAi0fppqgQ=="
- },
- "node_modules/tslib": {
- "version": "2.5.3",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz",
- "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w=="
- },
- "node_modules/undici": {
- "version": "5.22.1",
- "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz",
- "integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==",
- "dependencies": {
- "busboy": "^1.6.0"
- },
- "engines": {
- "node": ">=14.0"
- }
- },
- "node_modules/util-deprecate": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
- },
- "node_modules/webidl-conversions": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
- "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/whatwg-url": {
- "version": "11.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz",
- "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==",
- "dependencies": {
- "tr46": "^3.0.0",
- "webidl-conversions": "^7.0.0"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/ws": {
- "version": "8.13.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
- "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
- "engines": {
- "node": ">=10.0.0"
- },
- "peerDependencies": {
- "bufferutil": "^4.0.1",
- "utf-8-validate": ">=5.0.2"
- },
- "peerDependenciesMeta": {
- "bufferutil": {
- "optional": true
- },
- "utf-8-validate": {
- "optional": true
- }
- }
- }
- },
- "dependencies": {
- "@discordjs/builders": {
- "version": "1.6.3",
- "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.6.3.tgz",
- "integrity": "sha512-CTCh8NqED3iecTNuiz49mwSsrc2iQb4d0MjMdmS/8pb69Y4IlzJ/DIy/p5GFlgOrFbNO2WzMHkWKQSiJ3VNXaw==",
- "requires": {
- "@discordjs/formatters": "^0.3.1",
- "@discordjs/util": "^0.3.1",
- "@sapphire/shapeshift": "^3.8.2",
- "discord-api-types": "^0.37.41",
- "fast-deep-equal": "^3.1.3",
- "ts-mixer": "^6.0.3",
- "tslib": "^2.5.0"
- }
- },
- "@discordjs/collection": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.1.tgz",
- "integrity": "sha512-aWEc9DCf3TMDe9iaJoOnO2+JVAjeRNuRxPZQA6GVvBf+Z3gqUuWYBy2NWh4+5CLYq5uoc3MOvUQ5H5m8CJBqOA=="
- },
- "@discordjs/formatters": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.3.1.tgz",
- "integrity": "sha512-M7X4IGiSeh4znwcRGcs+49B5tBkNDn4k5bmhxJDAUhRxRHTiFAOTVUNQ6yAKySu5jZTnCbSvTYHW3w0rAzV1MA==",
- "requires": {
- "discord-api-types": "^0.37.41"
- }
- },
- "@discordjs/rest": {
- "version": "1.7.1",
- "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-1.7.1.tgz",
- "integrity": "sha512-Ofa9UqT0U45G/eX86cURQnX7gzOJLG2oC28VhIk/G6IliYgQF7jFByBJEykPSHE4MxPhqCleYvmsrtfKh1nYmQ==",
- "requires": {
- "@discordjs/collection": "^1.5.1",
- "@discordjs/util": "^0.3.0",
- "@sapphire/async-queue": "^1.5.0",
- "@sapphire/snowflake": "^3.4.2",
- "discord-api-types": "^0.37.41",
- "file-type": "^18.3.0",
- "tslib": "^2.5.0",
- "undici": "^5.22.0"
- }
- },
- "@discordjs/util": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-0.3.1.tgz",
- "integrity": "sha512-HxXKYKg7vohx2/OupUN/4Sd02Ev3PBJ5q0gtjdcvXb0ErCva8jNHWfe/v5sU3UKjIB/uxOhc+TDOnhqffj9pRA=="
- },
- "@discordjs/ws": {
- "version": "0.8.3",
- "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-0.8.3.tgz",
- "integrity": "sha512-hcYtppanjHecbdNyCKQNH2I4RP9UrphDgmRgLYrATEQF1oo4sYSve7ZmGsBEXSzH72MO2tBPdWSThunbxUVk0g==",
- "requires": {
- "@discordjs/collection": "^1.5.1",
- "@discordjs/rest": "^1.7.1",
- "@discordjs/util": "^0.3.1",
- "@sapphire/async-queue": "^1.5.0",
- "@types/ws": "^8.5.4",
- "@vladfrangu/async_event_emitter": "^2.2.1",
- "discord-api-types": "^0.37.41",
- "tslib": "^2.5.0",
- "ws": "^8.13.0"
- }
- },
- "@mongodb-js/saslprep": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.0.tgz",
- "integrity": "sha512-Xfijy7HvfzzqiOAhAepF4SGN5e9leLkMvg/OPOF97XemjfVCYN/oWa75wnkc6mltMSTwY+XlbhWgUOJmkFspSw==",
- "optional": true,
- "requires": {
- "sparse-bitfield": "^3.0.3"
- }
- },
- "@revanced-helper/helper-client": {
- "version": "1.0.0",
- "requires": {
- "bson": "^4.7.0"
- },
- "dependencies": {
- "bson": {
- "version": "4.7.2",
- "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.2.tgz",
- "integrity": "sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ==",
- "requires": {
- "buffer": "^5.6.0"
- }
- }
- }
- },
- "@sapphire/async-queue": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz",
- "integrity": "sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA=="
- },
- "@sapphire/shapeshift": {
- "version": "3.9.2",
- "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.2.tgz",
- "integrity": "sha512-YRbCXWy969oGIdqR/wha62eX8GNHsvyYi0Rfd4rNW6tSVVa8p0ELiMEuOH/k8rgtvRoM+EMV7Csqz77YdwiDpA==",
- "requires": {
- "fast-deep-equal": "^3.1.3",
- "lodash": "^4.17.21"
- }
- },
- "@sapphire/snowflake": {
- "version": "3.5.1",
- "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.1.tgz",
- "integrity": "sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA=="
- },
- "@tokenizer/token": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz",
- "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="
- },
- "@types/node": {
- "version": "20.2.5",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.5.tgz",
- "integrity": "sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ=="
- },
- "@types/webidl-conversions": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
- "integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog=="
- },
- "@types/whatwg-url": {
- "version": "8.2.2",
- "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz",
- "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==",
- "requires": {
- "@types/node": "*",
- "@types/webidl-conversions": "*"
- }
- },
- "@types/ws": {
- "version": "8.5.4",
- "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz",
- "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==",
- "requires": {
- "@types/node": "*"
- }
- },
- "@vierofernando/decancer-android-arm-eabi": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/@vierofernando/decancer-android-arm-eabi/-/decancer-android-arm-eabi-1.6.5.tgz",
- "integrity": "sha512-/xPMebqSFb6fePZdwD9Pz8pIc9GkCGlMOQA4ucFtKeepQrMhoil4qN+ri5DUSeW9PFvnj/cEWuPEeNDbFc4WyA==",
- "optional": true
- },
- "@vierofernando/decancer-android-arm64": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/@vierofernando/decancer-android-arm64/-/decancer-android-arm64-1.6.5.tgz",
- "integrity": "sha512-FraWlT6lfjFuV5L383+XzzFD5I2pzZ5TRDfix4BVXvDxjnO8ZKt4AB7DbWteDVu18zZbuVpBh3Tp1Eu1adidUg==",
- "optional": true
- },
- "@vierofernando/decancer-darwin-arm64": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/@vierofernando/decancer-darwin-arm64/-/decancer-darwin-arm64-1.6.5.tgz",
- "integrity": "sha512-pOarySDUPdxf/YQ673HxH+tJubapiiPt7SOuK8lRw3NoiQZ3cOf/LofU8rEUgK/yKfDyWbmQLnvMi1Hl1JTmhg==",
- "optional": true
- },
- "@vierofernando/decancer-darwin-x64": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/@vierofernando/decancer-darwin-x64/-/decancer-darwin-x64-1.6.5.tgz",
- "integrity": "sha512-B7JzUC5EHQtA7yJOrdRrKjHWBbzvBaPNAKHBKJ+brAwqa3yStpBodJZTgsfGHidCY8Gje0pGxSZVbPnGs+5Xbg==",
- "optional": true
- },
- "@vierofernando/decancer-linux-arm-gnueabihf": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/@vierofernando/decancer-linux-arm-gnueabihf/-/decancer-linux-arm-gnueabihf-1.6.5.tgz",
- "integrity": "sha512-1ALPTMzUo750lIuHn/paZ2wq+GkDXv15dP9w4bmP3ytrYVj8b0uJmb57FexNEIMPf4M0gkGmyNLjq+Y1AJoQvw==",
- "optional": true
- },
- "@vierofernando/decancer-linux-arm64-gnu": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/@vierofernando/decancer-linux-arm64-gnu/-/decancer-linux-arm64-gnu-1.6.5.tgz",
- "integrity": "sha512-RDNTJ9812zlQkWRxZS513xZoSUeRbONzcFX6VDnl/Lx20NVRZOryF8o4EtKDwzEd3kQrIr2tQlZyLLLsTGL48g==",
- "optional": true
- },
- "@vierofernando/decancer-linux-arm64-musl": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/@vierofernando/decancer-linux-arm64-musl/-/decancer-linux-arm64-musl-1.6.5.tgz",
- "integrity": "sha512-Qnm6yQxvUF8uojyIIUiZepTZIyJN2jdqvm2QptxfB1LGABkWCpTlv+xml8KTPFTUcPT1Epwye1FaVEwd90W7VQ==",
- "optional": true
- },
- "@vierofernando/decancer-linux-x64-gnu": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/@vierofernando/decancer-linux-x64-gnu/-/decancer-linux-x64-gnu-1.6.5.tgz",
- "integrity": "sha512-eKdF0jsdVpm+lcDHALqtH79Z8vPX5qsoJHM2YHrQ5pJ3khP2+OcEYdAyis2rl438OK6NJyQZfECSUSj9dtfAeQ==",
- "optional": true
- },
- "@vierofernando/decancer-linux-x64-musl": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/@vierofernando/decancer-linux-x64-musl/-/decancer-linux-x64-musl-1.6.5.tgz",
- "integrity": "sha512-RaJoJSIkLSu0l4tODVFWoeE+4BSVjHUn+Gb3yQKn5DHmsl1/EOuj6rlwX6uddleV9aQIDEAljSL3SExNZbmm2A==",
- "optional": true
- },
- "@vierofernando/decancer-win32-arm64-msvc": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/@vierofernando/decancer-win32-arm64-msvc/-/decancer-win32-arm64-msvc-1.6.5.tgz",
- "integrity": "sha512-SXI6r8m+J4vYCvjKQeafukSpBORU9wzM38SkBhjdp8wfcHVYfjVtoHVr4JxkpNfMJoIhv9j2MJYIaYVExvw8pg==",
- "optional": true
- },
- "@vierofernando/decancer-win32-ia32-msvc": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/@vierofernando/decancer-win32-ia32-msvc/-/decancer-win32-ia32-msvc-1.6.5.tgz",
- "integrity": "sha512-Ml6Gx6iwOzLopcH8BEd3Kn2MQ1bg5S4mKHQrxNn2MK3SqCLNzZKZhoWe18aCzaKLnwTTkcZvXNcZk1OLPLxmUw==",
- "optional": true
- },
- "@vierofernando/decancer-win32-x64-msvc": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/@vierofernando/decancer-win32-x64-msvc/-/decancer-win32-x64-msvc-1.6.5.tgz",
- "integrity": "sha512-fnMKkLkYJ/K/e1jo6WfwpoI4eNEkcWsA/rJMMF6XGLD6YhHnZZdlugqsbSK8j4GiBBTfgj6yCeCMEfLe2QP15w==",
- "optional": true
- },
- "@vladfrangu/async_event_emitter": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.2.tgz",
- "integrity": "sha512-HIzRG7sy88UZjBJamssEczH5q7t5+axva19UbZLO6u0ySbYPrwzWiXBcC0WuHyhKKoeCyneH+FvYzKQq/zTtkQ=="
- },
- "base64-js": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
- "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
- },
- "bson": {
- "version": "5.4.0",
- "resolved": "https://registry.npmjs.org/bson/-/bson-5.4.0.tgz",
- "integrity": "sha512-WRZ5SQI5GfUuKnPTNmAYPiKIof3ORXAF4IRU5UcgmivNIon01rWQlw5RUH954dpu8yGL8T59YShVddIPaU/gFA=="
- },
- "buffer": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
- "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
- "requires": {
- "base64-js": "^1.3.1",
- "ieee754": "^1.1.13"
- }
- },
- "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"
- }
- },
- "decancer": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/decancer/-/decancer-1.6.5.tgz",
- "integrity": "sha512-7p9ShXWXwKwTIwa5VoFtvUpIWMI4MEgCYLJqOwczBDyEHR65GhTxW/l0V/fazxV3w9KvlmoHI0HtTTI3nSNy1A==",
- "requires": {
- "@vierofernando/decancer-android-arm-eabi": "1.6.5",
- "@vierofernando/decancer-android-arm64": "1.6.5",
- "@vierofernando/decancer-darwin-arm64": "1.6.5",
- "@vierofernando/decancer-darwin-x64": "1.6.5",
- "@vierofernando/decancer-linux-arm-gnueabihf": "1.6.5",
- "@vierofernando/decancer-linux-arm64-gnu": "1.6.5",
- "@vierofernando/decancer-linux-arm64-musl": "1.6.5",
- "@vierofernando/decancer-linux-x64-gnu": "1.6.5",
- "@vierofernando/decancer-linux-x64-musl": "1.6.5",
- "@vierofernando/decancer-win32-arm64-msvc": "1.6.5",
- "@vierofernando/decancer-win32-ia32-msvc": "1.6.5",
- "@vierofernando/decancer-win32-x64-msvc": "1.6.5"
- }
- },
- "discord-api-types": {
- "version": "0.37.43",
- "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.43.tgz",
- "integrity": "sha512-bBhDWU3TF9KADxR/mHp1K4Bvu/LRtFQdGyBjADu4e66F3ZnD4kp12W/SJCttIaCcMXzPV3sfty6eDGRNRph51Q=="
- },
- "discord.js": {
- "version": "14.11.0",
- "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.11.0.tgz",
- "integrity": "sha512-CkueWYFQ28U38YPR8HgsBR/QT35oPpMbEsTNM30Fs8loBIhnA4s70AwQEoy6JvLcpWWJO7GY0y2BUzZmuBMepQ==",
- "requires": {
- "@discordjs/builders": "^1.6.3",
- "@discordjs/collection": "^1.5.1",
- "@discordjs/formatters": "^0.3.1",
- "@discordjs/rest": "^1.7.1",
- "@discordjs/util": "^0.3.1",
- "@discordjs/ws": "^0.8.3",
- "@sapphire/snowflake": "^3.4.2",
- "@types/ws": "^8.5.4",
- "discord-api-types": "^0.37.41",
- "fast-deep-equal": "^3.1.3",
- "lodash.snakecase": "^4.1.1",
- "tslib": "^2.5.0",
- "undici": "^5.22.0",
- "ws": "^8.13.0"
- }
- },
- "fast-deep-equal": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
- },
- "file-type": {
- "version": "18.5.0",
- "resolved": "https://registry.npmjs.org/file-type/-/file-type-18.5.0.tgz",
- "integrity": "sha512-yvpl5U868+V6PqXHMmsESpg6unQ5GfnPssl4dxdJudBrr9qy7Fddt7EVX1VLlddFfe8Gj9N7goCZH22FXuSQXQ==",
- "requires": {
- "readable-web-to-node-stream": "^3.0.2",
- "strtok3": "^7.0.0",
- "token-types": "^5.0.1"
- }
- },
- "ieee754": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
- "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
- },
- "inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
- },
- "ip": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz",
- "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ=="
- },
- "lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
- },
- "lodash.snakecase": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz",
- "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw=="
- },
- "memory-pager": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
- "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
- "optional": true
- },
- "mongodb": {
- "version": "5.8.1",
- "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.8.1.tgz",
- "integrity": "sha512-wKyh4kZvm6NrCPH8AxyzXm3JBoEf4Xulo0aUWh3hCgwgYJxyQ1KLST86ZZaSWdj6/kxYUA3+YZuyADCE61CMSg==",
- "requires": {
- "@mongodb-js/saslprep": "^1.1.0",
- "bson": "^5.4.0",
- "mongodb-connection-string-url": "^2.6.0",
- "socks": "^2.7.1"
- }
- },
- "mongodb-connection-string-url": {
- "version": "2.6.0",
- "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz",
- "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==",
- "requires": {
- "@types/whatwg-url": "^8.2.1",
- "whatwg-url": "^11.0.0"
- }
- },
- "parse-duration": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/parse-duration/-/parse-duration-1.1.0.tgz",
- "integrity": "sha512-z6t9dvSJYaPoQq7quMzdEagSFtpGu+utzHqqxmpVWNNZRIXnvqyCvn9XsTdh7c/w0Bqmdz3RB3YnRaKtpRtEXQ=="
- },
- "peek-readable": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz",
- "integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A=="
- },
- "punycode": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
- "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA=="
- },
- "readable-stream": {
- "version": "3.6.2",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
- "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
- "requires": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- }
- },
- "readable-web-to-node-stream": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz",
- "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==",
- "requires": {
- "readable-stream": "^3.6.0"
- }
- },
- "safe-buffer": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
- },
- "smart-buffer": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
- "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="
- },
- "socks": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz",
- "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==",
- "requires": {
- "ip": "^2.0.0",
- "smart-buffer": "^4.2.0"
- }
- },
- "sparse-bitfield": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
- "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
- "optional": true,
- "requires": {
- "memory-pager": "^1.0.2"
- }
- },
- "streamsearch": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
- "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="
- },
- "string_decoder": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
- "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
- "requires": {
- "safe-buffer": "~5.2.0"
- }
- },
- "strtok3": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz",
- "integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==",
- "requires": {
- "@tokenizer/token": "^0.3.0",
- "peek-readable": "^5.0.0"
- }
- },
- "token-types": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz",
- "integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==",
- "requires": {
- "@tokenizer/token": "^0.3.0",
- "ieee754": "^1.2.1"
- }
- },
- "tr46": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz",
- "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==",
- "requires": {
- "punycode": "^2.1.1"
- }
- },
- "ts-mixer": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz",
- "integrity": "sha512-k43M7uCG1AkTyxgnmI5MPwKoUvS/bRvLvUb7+Pgpdlmok8AoqmUaZxUUw8zKM5B1lqZrt41GjYgnvAi0fppqgQ=="
- },
- "tslib": {
- "version": "2.5.3",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz",
- "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w=="
- },
- "undici": {
- "version": "5.22.1",
- "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz",
- "integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==",
- "requires": {
- "busboy": "^1.6.0"
- }
- },
- "util-deprecate": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
- },
- "webidl-conversions": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
- "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="
- },
- "whatwg-url": {
- "version": "11.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz",
- "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==",
- "requires": {
- "tr46": "^3.0.0",
- "webidl-conversions": "^7.0.0"
- }
- },
- "ws": {
- "version": "8.13.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
- "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
- "requires": {}
- }
- }
-}
diff --git a/apps/bot-discord/src/package.json b/apps/bot-discord/src/package.json
deleted file mode 100644
index d7b0df5..0000000
--- a/apps/bot-discord/src/package.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "name": "bot-discord",
- "version": "1.0.0",
- "description": "",
- "main": "index.js",
- "type": "module",
- "keywords": [],
- "author": "Reis Can",
- "license": "GPL-3.0-or-later",
- "dependencies": {
- "@revanced-helper/helper-client": "file:../../../packages/client",
- "decancer": "^1.6.5",
- "discord.js": "^14.11.0",
- "mongodb": "^5.7.0",
- "parse-duration": "^1.1.0"
- }
-}
diff --git a/apps/bot-discord/src/registerCommands.js b/apps/bot-discord/src/registerCommands.js
deleted file mode 100644
index 1cea873..0000000
--- a/apps/bot-discord/src/registerCommands.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import { REST, Routes } from 'discord.js';
-import { readdirSync, readFileSync } from 'node:fs';
-const configJSON = readFileSync('./config.json', 'utf-8');
-const config = JSON.parse(configJSON);
-
-const commands = [];
-// Grab all the command files from the commands directory you created earlier
-const commandFiles = readdirSync('./commands').filter((file) =>
- file.endsWith('.js')
-);
-
-// Grab the SlashCommandBuilder#toJSON() output of each command's data for deployment
-for (const file of commandFiles) {
- const command = await import(`./commands/${file}`);
- if (!command.default.data.toJSON) continue;
- commands.push(command.default.data.toJSON());
-}
-
-// Construct and prepare an instance of the REST module
-const rest = new REST({ version: '10' }).setToken(process.env.DISCORD_TOKEN);
-
-try {
- console.log(
- `Started refreshing ${commands.length} application (/) commands.`
- );
-
- // The put method is used to fully refresh all commands in the guild with the current set
- const data = await rest.put(Routes.applicationCommands(config.discord.botId), {
- body: commands
- });
-
- console.log(`Successfully reloaded ${data.length} application (/) commands.`);
-} catch (error) {
- // And of course, make sure you catch and log any errors!
- console.error(error);
-}
\ No newline at end of file
diff --git a/apps/bot-discord/src/utils/checkModPerms.js b/apps/bot-discord/src/utils/checkModPerms.js
deleted file mode 100644
index 6907adb..0000000
--- a/apps/bot-discord/src/utils/checkModPerms.js
+++ /dev/null
@@ -1,8 +0,0 @@
-export function checkForPerms(config, member) {
- for (const role of config.discord.modRoles) {
- if (member.roles.cache.has(role)) {
- return true;
- }
- }
- return false;
-}
\ No newline at end of file
diff --git a/apps/bot-discord/src/utils/checkSupporterPerms.js b/apps/bot-discord/src/utils/checkSupporterPerms.js
deleted file mode 100644
index 6deadd3..0000000
--- a/apps/bot-discord/src/utils/checkSupporterPerms.js
+++ /dev/null
@@ -1,8 +0,0 @@
-export function checkForPerms(config, member) {
- for (const role of config.discord.trainRoles) {
- if (member.roles.cache.has(role)) {
- return true;
- }
- }
- return false;
-}
\ No newline at end of file
diff --git a/apps/bot-discord/src/utils/cureUsername.js b/apps/bot-discord/src/utils/cureUsername.js
deleted file mode 100644
index f0b32f2..0000000
--- a/apps/bot-discord/src/utils/cureUsername.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import decancer from 'decancer';
-
-export default async function cureUsername(member) {
- let toCure = member.user.displayName;
- if (member.nickname) toCure = member.nickname;
-
- if (!/^[\x20-\x7D]+$/.test(toCure)) {
- // Cure username/nickname if there's non-ascii characters.
-
- let curedName = decancer(toCure).toString();
-
- // If the output is empty, rename them to "ReVanced member".
- if (/^\s*$/.test(curedName)) curedName = 'ReVanced member';
-
- member.setNickname(curedName);
- }
-}
\ No newline at end of file
diff --git a/apps/bot-discord/src/utils/exileMemberToChannel.js b/apps/bot-discord/src/utils/exileMemberToChannel.js
deleted file mode 100644
index 8cbfaac..0000000
--- a/apps/bot-discord/src/utils/exileMemberToChannel.js
+++ /dev/null
@@ -1,47 +0,0 @@
-export default async function exileMemberToChannel(member, channel, message, reason, config) {
- const redirectChannel = await channel.client.channels.fetch(config.discord.supportChannel);
-
- let messageContent = '';
- if (Array.isArray(message)) {
- for (const msg of message) {
- messageContent += `${msg}\n`;
- }
- } else if (!message) {
- message = 'No message provided'
- } else messageContent = message;
-
- const embedFields = [
- {
- name: 'Orginal message',
- value: messageContent
- }
- ];
-
- if (reason) {
- embedFields.push(
- {
- name: 'Reason',
- value: reason
- }
- );
- }
-
-
- await redirectChannel.send({
- content: `<@${member.id}>`,
- embeds: [
- {
- title: `Restricted to <#${redirectChannel.id}>`,
- fields: embedFields,
- thumbnail: {
- url: member.avatarURL()
- },
- footer: {
- text: 'ReVanced',
- icon_url: channel.client.user.avatarURL()
- },
- color: 5150960
- }
- ]
- });
-}
\ No newline at end of file
diff --git a/apps/bot-discord/src/utils/muteMember.js b/apps/bot-discord/src/utils/muteMember.js
deleted file mode 100644
index 5765c65..0000000
--- a/apps/bot-discord/src/utils/muteMember.js
+++ /dev/null
@@ -1,87 +0,0 @@
-import parse from 'parse-duration'
-import setMuteTimeout from './setMuteTimeout.js';
-
-parse['mo'] = parse['month']
-
-export default async function muteMember(config, member, { duration, reason, supportMute, guild }) {
- let expires;
-
- if (supportMute) {
- expires = Math.floor((Date.now() + config.discord.mute.supportMuteDuration) / 1000);
- } else {
- const parsedDuration = parse(duration);
- expires = Math.floor((Date.now() + parsedDuration) / 1000);
- }
-
- const takenRoles = [];
- for (const takeRole of supportMute ?
- config.discord.mute.supportTakeRoles :
- config.discord.mute.takeRoles
- ) {
- if (member.roles.cache.get(takeRole)) {
- takenRoles.push(takeRole);
- }
- }
-
- const existingMute = await guild.client.db.collection('muted').findOne({
- guild_id: guild.id,
- user_id: member.id
- });
-
- if (existingMute) {
- // Update existing mute
-
- await guild.client.db.collection('muted').updateOne({
- guild_id: guild.id,
- user_id: member.id
- }, {
- $set: {
- reason,
- expires,
- support_mute: supportMute
- }
- });
-
- if (guild.client.mutes.has(member.id)) {
- clearTimeout(guild.client.mutes.get(member.id))
- guild.client.mutes.delete(member.id);
- }
- } else {
- await guild.client.db.collection('muted').insertOne({
- guild_id: guild.id,
- user_id: member.id,
- taken_roles: takenRoles,
- expires,
- reason,
- support_mute: supportMute
- });
- }
-
- // Remove the roles, give defined roles.
- if (!existingMute) {
- const currentRoles = member.roles.cache.map((role) => role.id);
- let setRoles = [];
- for (const role of currentRoles) {
- if (takenRoles.includes(role)) continue;
- setRoles.push(role);
- }
-
- setRoles = setRoles.concat(supportMute ?
- config.discord.mute.supportGiveRoles :
- config.discord.mute.giveRoles)
- await member.roles.set(setRoles);
- }
-
-
- // Start a timeout.
- setMuteTimeout({
- guild_id: guild.id,
- user_id: member.id,
- taken_roles: takenRoles,
- expires,
- support_mute: supportMute
- }, guild.client, config);
-
- // Return parsed time for the mute command to resolve.
- return expires;
-}
\ No newline at end of file
diff --git a/apps/bot-discord/src/utils/reportToLogs.js b/apps/bot-discord/src/utils/reportToLogs.js
deleted file mode 100644
index 6e7db8b..0000000
--- a/apps/bot-discord/src/utils/reportToLogs.js
+++ /dev/null
@@ -1,45 +0,0 @@
-import { EmbedBuilder, messageLink } from 'discord.js';
-
-export default async function reportToLogs(config, client, action, message, { reason, expire, actionTo, actionBy }, interaction, commandMsg) {
- const actionUpper = action.charAt(0).toUpperCase() + action.slice(1);
- const actionTitle = `${actionUpper} ${actionTo.tag}`;
- const actionEmbed = new EmbedBuilder()
- .setThumbnail(actionTo.avatarURL())
- .setTitle(actionTitle)
- .setColor(5150960)
- .setFooter({ text: 'ReVanced', iconURL: client.user.avatarURL() });
-
- const fields = [
- { name: 'Action', value: `${actionTo.toString()} was ${action} by ${actionBy.toString()}` }
- ];
-
- if (action === 'banned' || action === 'muted' || action === 'exiled') fields.push({
- name: 'Reason',
- value: reason ? reason : 'No reason provided',
- inline: true
- });
-
- if (expire) fields.push({ name: 'Expires', value: ``, inline: true });
-
- if (message) fields.push({ name: 'Reference', value: `[Jump to message](${messageLink(
- message.channelId,
- message.id,
- message.guild.id)})`,
- inline: true
- });
-
- actionEmbed.setFields(fields);
-
- if (interaction) {
- await interaction.editReply({ embeds: [actionEmbed] });
- const msg = await interaction.fetchReply();
- reportToLogs(config, client, action, msg, { reason, expire, actionTo, actionBy });
- } else if (commandMsg) {
- const msg = await commandMsg.reply({ embeds: [actionEmbed] });
- reportToLogs(config, client, action, msg, { reason, expire, actionTo, actionBy });
- } else {
- const channel = await client.channels.fetch(config.logs.channelId);
- const thread = await channel.threads.fetch(config.logs.threadId);
- thread.send({ embeds: [actionEmbed] });
- }
-}
\ No newline at end of file
diff --git a/apps/bot-discord/src/utils/setMuteTimeout.js b/apps/bot-discord/src/utils/setMuteTimeout.js
deleted file mode 100644
index 415638d..0000000
--- a/apps/bot-discord/src/utils/setMuteTimeout.js
+++ /dev/null
@@ -1,24 +0,0 @@
-export default async function setMuteTimeout(mute, client, config) {
- const duration = (mute.expires - Math.floor(new Date() / 1000)) * 1000;
- client.mutes.set(mute.user_id, setTimeout(async() => {
- const guild = await client.guilds.fetch(mute.guild_id);
- let member;
- try {
- member = await guild.members.fetch(mute.user_id);
- } catch (_) {
- return;
- }
-
- member.roles.add(mute.taken_roles);
- member.roles.remove(
- mute.support_mute ?
- config.discord.mute.supportGiveRoles :
- config.discord.mute.giveRoles
- );
-
- client.db.collection('muted').deleteOne({
- user_id: mute.user_id,
- guild_id: mute.guild_id
- });
- }, duration));
-}
\ No newline at end of file
diff --git a/apps/bot-discord/src/utils/trainAISelectMenu.js b/apps/bot-discord/src/utils/trainAISelectMenu.js
deleted file mode 100644
index 9e36c28..0000000
--- a/apps/bot-discord/src/utils/trainAISelectMenu.js
+++ /dev/null
@@ -1,77 +0,0 @@
-import {
- ActionRowBuilder,
- StringSelectMenuBuilder,
- ComponentType
-} from 'discord.js';
-
-export default async function trainAISelectMenu(
- interaction,
- config,
- helper
-) {
- const options = [];
-
- for (const { label } of config.responses) {
- options.push({
- label: label,
- description: `The ${label} label.`,
- value: label.toLowerCase()
- });
- }
-
- const row = new ActionRowBuilder().addComponents(
- new StringSelectMenuBuilder()
- .setCustomId('select')
- .setPlaceholder('Nothing selected')
- .addOptions(options)
- );
-
- let interactedMessage;
-
- if (!interaction.isMessageContextMenuCommand()) {
- try {
- const channel = await interaction.client.channels.fetch(interaction.message.reference.channelId);
- const message = await channel.messages.fetch(interaction.message.reference.messageId);
- interactedMessage = message.content.toLowerCase();
- } catch (e) {
- interaction.reply({
- content: 'The message that you wanted to train the bot with was deleted.',
- ephemeral: true
- })
- }
-
- } else {
- interactedMessage = interaction.targetMessage.content.toLowerCase()
- }
-
- const reply = await interaction.reply({
- content: 'Please select the corresponding label to train the bot.',
- components: [row],
- ephemeral: true
- });
-
- const collector = reply.createMessageComponentCollector({
- componentType: ComponentType.StringSelect,
- time: 30000
- });
-
- const voteId = interaction.targetMessage ? interaction.targetMessage.id :
- interaction.message.reference.messageId;
- collector.on('collect', (i) => {
- interaction.editReply({ content: 'Sent training data to server.', components: [] });
-
- const existingVote = interaction.client.trainingVotes.get(voteId);
- if (existingVote) clearTimeout(existingVote);
- interaction.client.trainingVotes.set(voteId,
- setTimeout(() => {
- helper.sendTrainData(interactedMessage, i.values[0]);
-
- if (!interaction.isMessageContextMenuCommand()) {
- interaction.message.edit({ components: [] });
- }
-
- interaction.client.trainingVotes.delete(voteId);
- }, 10_000)
- );
- });
-}
diff --git a/apps/bot-discord/src/utils/unmuteMember.js b/apps/bot-discord/src/utils/unmuteMember.js
deleted file mode 100644
index 23499f4..0000000
--- a/apps/bot-discord/src/utils/unmuteMember.js
+++ /dev/null
@@ -1,24 +0,0 @@
-export default async function unmuteMember(config, member, supportMute) {
- const mute = await member.client.db.collection('muted').findOne({
- guild_id: member.guild.id,
- user_id: member.id
- });
-
- if (!mute) return false;
- if (supportMute) {
- if (!mute.support_mute) return false;
- }
-
- member.roles.remove(mute.support_mute ?
- config.discord.mute.supportGiveRoles :
- config.discord.mute.giveRoles
- );
-
- member.roles.add(mute.taken_roles);
-
- await member.client.db.collection('muted').deleteOne({
- user_id: member.id
- });
-
- return true;
-}
\ No newline at end of file
diff --git a/apps/bot-telegram/src/commands/train.js b/apps/bot-telegram/src/commands/train.js
deleted file mode 100644
index ddde333..0000000
--- a/apps/bot-telegram/src/commands/train.js
+++ /dev/null
@@ -1,61 +0,0 @@
-export default {
- command: /\/train/,
- async execute(bot, config, msg) {
- const admins = await bot.getChatAdministrators(msg.chat.id);
- const isAdmin = admins.find((admin) => admin.user.id === msg.from.id);
-
- if (!isAdmin)
- return bot.sendMessage(msg.chat.id, 'You\'re not an admin.', {
- message_thread_id: msg.message_thread_id,
- reply_to_message_id: msg.message_id
- });
-
- if (msg.reply_to_message.message_id === msg.message_thread_id)
- return bot.sendMessage(msg.chat.id, 'Please reply to a message!', {
- message_thread_id: msg.message_thread_id,
- reply_to_message_id: msg.message_id
- });
-
- const options = [];
- let arrI = 0;
- let i = 0;
- for (const { label } of config.responses) {
- if (arrI === 0 && i === 0) {
- options.push([
- {
- text: label,
- callback_data: `label_${label.toLowerCase()}`
- }
- ]);
- i++;
- } else if (i === 2) {
- options.push([
- {
- text: label,
- callback_data: `label_${label.toLowerCase()}`
- }
- ]);
- i = 0;
- arrI++;
- } else {
- options[arrI].push({
- text: label,
- callback_data: `label_${label.toLowerCase()}`
- });
- i++;
- }
- }
-
- bot.sendMessage(
- msg.chat.id,
- 'Please select the corresponding label to train the bot.',
- {
- message_thread_id: msg.message_thread_id,
- reply_to_message_id: msg.reply_to_message.message_id,
- reply_markup: {
- inline_keyboard: options
- }
- }
- );
- }
-};
diff --git a/apps/bot-telegram/src/config.example.json b/apps/bot-telegram/src/config.example.json
deleted file mode 100644
index bd1706f..0000000
--- a/apps/bot-telegram/src/config.example.json
+++ /dev/null
@@ -1,109 +0,0 @@
-{
- "server": {
- "port": 3000,
- "host": "127.0.0.1"
- },
- "responses": [
- {
- "label": "revanced_crash",
- "threshold": 0.85,
- "reply": {
- "title": "Why is my patched app crashing?",
- "description": "It seems like your patched application is crashing, these might be the reason why:\n * You patched a non-suggested version.\n * Patches failed to apply.\n * Non-default patches were used.\n * Split APK was used."
- }
- },
- {
- "label": "rvmanager_abort",
- "threshold": 0.85,
- "reply": {
- "title": "Why is ReVanced Manager aborting?",
- "description": "It seems like your Manager is aborting. If you see the text \"exit code = 135\" or \"exit code = 139\", then your device's architecture is not supported. Please patch on another device or on your PC."
- }
- },
- {
- "label": "revanced_download",
- "threshold": 0.85,
- "reply": {
- "title": "How to download ReVanced?",
- "description": "ReVanced is a patcher. You can use the [ReVanced Manager](https://github.com/revanced/revanced-manager/releases/latest) or the [ReVanced CLI](https://github.com/revanced/revanced-cli) to patch the app you want to modify.\n* [ReVanced Manager docs](https://github.com/revanced/revanced-manager/tree/main/docs#-revanced-manager)\n* [ReVanced CLI docs](https://github.com/revanced/revanced-cli/tree/main/docs#-documentation-and-guides-of-revanced-cli)"
- }
- },
- {
- "label": "androidtv_support",
- "threshold": 0.85,
- "reply": {
- "title": "Will YT ReVanced support Android TVs?",
- "description": "YouTube ReVanced for Android/Google TVs won't be made. There are alternatives, such as [SmartTubeNext](https://github.com/yuliskov/SmartTubeNext#smarttube)."
- }
- },
- {
- "label": "revanced_nodownloader",
- "threshold": 0.85,
- "reply": {
- "title": "Why can't I download videos?",
- "description": "You need to install a downloader to download videos. NewPipe is the default downloader, and it can be downloaded from [here](https://github.com/TeamNewPipe/NewPipe/releases/latest)."
- }
- },
- {
- "label": "revanced_casting",
- "threshold": 0.85,
- "reply": {
- "title": "Why can't I cast?",
- "description": "Because of devices like Chromecast, Android/Google TVs using the Cast v2 API, casting to those devices won't work."
- }
- },
- {
- "label": "microg_download",
- "threshold": 0.85,
- "reply": {
- "title": "From where can I download Vanced MicroG?",
- "description": "You can download Vanced MicroG from [here](https://github.com/TeamVanced/VancedMicroG/releases/latest)."
- }
- },
- {
- "label": "microg_nointernet",
- "threshold": 0.85,
- "reply": {
- "title": "Why does YT ReVanced say I'm offline?",
- "description": "If your YT ReVanced appears to not have internet and you recently changed your Google password, remove the Vanced MicroG account from within your device settings and then log back in."
- }
- },
- {
- "label": "rvdownload_unofficial",
- "threshold": 0.85,
- "reply": {
- "title": "What are the official ReVanced sites?",
- "description": "The official sites for ReVanced are [revanced.app](https://revanced.app) and [github.com/revanced](https://github.com/revanced)."
- }
- },
- {
- "label": "yt_buffering",
- "threshold": 0.85,
- "reply": {
- "title": "Why do videos fail to play?",
- "description": "Check [this announcement](https://t.me/app_revanced/19)."
- }
- },
- {
- "label": "false",
- "threshold": 0,
- "reply": null
- }
- ],
- "ocrResponses": [
- {
- "regex": "is not installed",
- "reply": {
- "title": "Why can't I download videos?",
- "description": "You need to install a downloader to download videos. NewPipe is the default downloader, and it can be downloaded from [here](https://github.com/TeamNewPipe/NewPipe/releases/latest)."
- }
- },
- {
- "regex": "You're offline|Please check your",
- "reply": {
- "title": "Why does YT ReVanced say I'm offline?",
- "description": "If your YT ReVanced appears to not have internet and you recently changed your Google password, remove the Vanced MicroG account from within your device settings and then log back in."
- }
- }
- ]
-}
\ No newline at end of file
diff --git a/apps/bot-telegram/src/events/callbackQuery.js b/apps/bot-telegram/src/events/callbackQuery.js
deleted file mode 100644
index 8368286..0000000
--- a/apps/bot-telegram/src/events/callbackQuery.js
+++ /dev/null
@@ -1,26 +0,0 @@
-export default {
- name: 'callback_query',
- once: false,
- async execute(bot, helper, cb) {
- const admins = await bot.getChatAdministrators(cb.message.chat.id);
- const isAdmin = admins.find((admin) => admin.user.id === cb.from.id);
-
- if (!isAdmin)
- return bot.sendMessage(cb.message.chat.id, 'You\'re not an admin.', {
- message_thread_id: cb.message.message_thread_id,
- reply_to_message_id: cb.message.message_id
- });
-
- helper.sendTrainData(
- cb.message.reply_to_message.text.toLowerCase(),
- cb.data.replace('label_', '').toUpperCase()
- );
-
- bot.sendMessage(cb.message.chat.id, 'Sent training data to server.', {
- message_thread_id: cb.message.message_thread_id,
- reply_to_message_id: cb.message.message_id
- });
-
- bot.deleteMessage(cb.message.chat.id, cb.message.message_id);
- }
-};
diff --git a/apps/bot-telegram/src/events/message.js b/apps/bot-telegram/src/events/message.js
deleted file mode 100644
index 53ceb03..0000000
--- a/apps/bot-telegram/src/events/message.js
+++ /dev/null
@@ -1,15 +0,0 @@
-export default {
- name: 'message',
- once: false,
- async execute(bot, helper, msg) {
- if (msg.photo) {
- const fileLink = await bot.getFileLink(msg.photo.at(-1).file_id);
- helper.scanImage(fileLink, `${msg.chat.id}/${msg.message_thread_id}/${msg.message_id}`)
- }
- if (!msg.text) return;
- helper.scanText(
- msg.text.toLowerCase(),
- `${msg.chat.id}/${msg.message_thread_id}/${msg.message_id}`
- );
- }
-};
diff --git a/apps/bot-telegram/src/helperEvents/aiResponse.js b/apps/bot-telegram/src/helperEvents/aiResponse.js
deleted file mode 100644
index e30322e..0000000
--- a/apps/bot-telegram/src/helperEvents/aiResponse.js
+++ /dev/null
@@ -1,28 +0,0 @@
-export default {
- name: 'aiResponse',
- once: false,
- async execute(bot, config, aiRes) {
- if (!aiRes.response) return;
- if (!aiRes.response[0]) return;
- const ids = aiRes.id.split('/');
- const intent = aiRes.response.reduce((a, b) =>
- a.confidence > b.confidence ? a : b
- );
- const response = config.responses.find((res) => res.label === intent.name);
- if (!response) return;
- if (response.threshold > intent.confidence) return;
- if (!response.reply) return;
-
- bot.sendMessage(
- ids[0],
- `**${response.reply.title}**\n\n${response.reply.description}\n`,
- {
- message_thread_id: ids[1],
- reply_to_message_id: ids[2],
- parse_mode: 'markdown'
- }
- );
-
- return;
- }
-};
diff --git a/apps/bot-telegram/src/helperEvents/ocrResponse.js b/apps/bot-telegram/src/helperEvents/ocrResponse.js
deleted file mode 100644
index e9c71de..0000000
--- a/apps/bot-telegram/src/helperEvents/ocrResponse.js
+++ /dev/null
@@ -1,24 +0,0 @@
-export default {
- name: 'ocrResponse',
- once: false,
- async execute(bot, config, ocrRes) {
- const ids = ocrRes.id.split('/');
-
- for (const ocrReply of config.ocrResponses) {
- if (ocrRes.ocrText.match(ocrReply.regex)) {
-
- bot.sendMessage(
- ids[0],
- `## ${ocrReply.reply.title}\n\n${ocrReply.reply.description}`,
- {
- message_thread_id: ids[1],
- reply_to_message_id: ids[2],
- parse_mode: 'markdown'
- }
- );
- break;
- }
- }
- return;
- }
-};
diff --git a/apps/bot-telegram/src/index.js b/apps/bot-telegram/src/index.js
deleted file mode 100644
index cfc9a99..0000000
--- a/apps/bot-telegram/src/index.js
+++ /dev/null
@@ -1,66 +0,0 @@
-import TelegramBot from 'node-telegram-bot-api';
-import { readFileSync, readdirSync } from 'node:fs';
-// Fix __dirname not being defined in ES modules. (https://stackoverflow.com/a/64383997)
-import { fileURLToPath } from 'node:url';
-import { dirname, join } from 'node:path';
-
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = dirname(__filename);
-import HelperClient from '@revanced-helper/helper-client';
-import config from './config.json' assert { type: 'json' };
-
-const helper = new HelperClient(config);
-helper.connect();
-
-const bot = new TelegramBot(process.env.TELEGRAM_TOKEN, { polling: true });
-
-const commandsPath = join(__dirname, 'commands');
-const commandFiles = readdirSync(commandsPath).filter((file) =>
- file.endsWith('.js')
-);
-
-for (const file of commandFiles) {
- const filePath = join(commandsPath, file);
- const command = (await import(`file://${filePath}`)).default;
- if ('command' in command && 'execute' in command) {
- bot.onText(command.command, (...args) =>
- command.execute(bot, config, ...args)
- );
- } else {
- console.log(
- `[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.`
- );
- }
-}
-
-const tgEventsPath = join(__dirname, 'events');
-const tgEventFiles = readdirSync(tgEventsPath).filter((file) =>
- file.endsWith('.js')
-);
-
-for (const file of tgEventFiles) {
- const filePath = join(tgEventsPath, file);
- const event = (await import(`file://${filePath}`)).default;
- if (event.once) {
- bot.once(event.name, (...args) => event.execute(bot, helper, ...args));
- } else {
- bot.on(event.name, (...args) => event.execute(bot, helper, ...args));
- }
-}
-
-// The ReVanced Helper events.
-
-const helperEventsPath = join(__dirname, 'helperEvents');
-const helperEventFiles = readdirSync(helperEventsPath).filter((file) =>
- file.endsWith('.js')
-);
-
-for (const file of helperEventFiles) {
- const filePath = join(helperEventsPath, file);
- const event = (await import(`file://${filePath}`)).default;
- if (event.once) {
- helper.once(event.name, (...args) => event.execute(bot, config, ...args));
- } else {
- helper.on(event.name, (...args) => event.execute(bot, config, ...args));
- }
-}
diff --git a/apps/bot-telegram/src/package-lock.json b/apps/bot-telegram/src/package-lock.json
deleted file mode 100644
index 822c834..0000000
--- a/apps/bot-telegram/src/package-lock.json
+++ /dev/null
@@ -1,2302 +0,0 @@
-{
- "name": "bot-telegram",
- "version": "1.0.0",
- "lockfileVersion": 2,
- "requires": true,
- "packages": {
- "": {
- "name": "bot-telegram",
- "version": "1.0.0",
- "license": "GPL-3.0-or-later",
- "dependencies": {
- "@revanced-helper/helper-client": "file:../../../packages/client",
- "node-telegram-bot-api": "^0.61.0"
- }
- },
- "../../../packages/client": {
- "name": "@revanced-helper/helper-client",
- "version": "1.0.0",
- "license": "GPL-3.0-or-later",
- "dependencies": {
- "bson": "^4.7.0"
- }
- },
- "node_modules/@revanced-helper/helper-client": {
- "resolved": "../../../packages/client",
- "link": true
- },
- "node_modules/ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "dependencies": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/epoberezkin"
- }
- },
- "node_modules/array-buffer-byte-length": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz",
- "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "is-array-buffer": "^3.0.1"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/array.prototype.findindex": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/array.prototype.findindex/-/array.prototype.findindex-2.2.1.tgz",
- "integrity": "sha512-tMj4uTmGpaGUh4XFMUh3H7KYAIqlygrlXchOEVTiICbTwRwMhDqtzsOwvtI+WAf1GdjJBeIP3Bu92Qg0SnXdtA==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4",
- "es-shim-unscopables": "^1.0.0"
- }
- },
- "node_modules/asn1": {
- "version": "0.2.6",
- "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
- "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
- "dependencies": {
- "safer-buffer": "~2.1.0"
- }
- },
- "node_modules/assert-plus": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
- "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==",
- "engines": {
- "node": ">=0.8"
- }
- },
- "node_modules/asynckit": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
- },
- "node_modules/available-typed-arrays": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
- "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/aws-sign2": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
- "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==",
- "engines": {
- "node": "*"
- }
- },
- "node_modules/aws4": {
- "version": "1.12.0",
- "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz",
- "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg=="
- },
- "node_modules/bcrypt-pbkdf": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
- "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
- "dependencies": {
- "tweetnacl": "^0.14.3"
- }
- },
- "node_modules/bl": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz",
- "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==",
- "dependencies": {
- "readable-stream": "^2.3.5",
- "safe-buffer": "^5.1.1"
- }
- },
- "node_modules/bluebird": {
- "version": "3.7.2",
- "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
- "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
- },
- "node_modules/call-bind": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
- "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
- "dependencies": {
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/caseless": {
- "version": "0.12.0",
- "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
- "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw=="
- },
- "node_modules/combined-stream": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
- "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
- "dependencies": {
- "delayed-stream": "~1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/core-util-is": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
- "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
- },
- "node_modules/dashdash": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
- "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==",
- "dependencies": {
- "assert-plus": "^1.0.0"
- },
- "engines": {
- "node": ">=0.10"
- }
- },
- "node_modules/debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "dependencies": {
- "ms": "^2.1.1"
- }
- },
- "node_modules/define-properties": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz",
- "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==",
- "dependencies": {
- "has-property-descriptors": "^1.0.0",
- "object-keys": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/delayed-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
- "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/ecc-jsbn": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
- "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==",
- "dependencies": {
- "jsbn": "~0.1.0",
- "safer-buffer": "^2.1.0"
- }
- },
- "node_modules/end-of-stream": {
- "version": "1.4.4",
- "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
- "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
- "dependencies": {
- "once": "^1.4.0"
- }
- },
- "node_modules/es-abstract": {
- "version": "1.21.2",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz",
- "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==",
- "dependencies": {
- "array-buffer-byte-length": "^1.0.0",
- "available-typed-arrays": "^1.0.5",
- "call-bind": "^1.0.2",
- "es-set-tostringtag": "^2.0.1",
- "es-to-primitive": "^1.2.1",
- "function.prototype.name": "^1.1.5",
- "get-intrinsic": "^1.2.0",
- "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.5",
- "is-array-buffer": "^3.0.2",
- "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.3",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.4",
- "regexp.prototype.flags": "^1.4.3",
- "safe-regex-test": "^1.0.0",
- "string.prototype.trim": "^1.2.7",
- "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": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/es-set-tostringtag": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz",
- "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==",
- "dependencies": {
- "get-intrinsic": "^1.1.3",
- "has": "^1.0.3",
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-shim-unscopables": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz",
- "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==",
- "dependencies": {
- "has": "^1.0.3"
- }
- },
- "node_modules/es-to-primitive": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
- "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
- "dependencies": {
- "is-callable": "^1.1.4",
- "is-date-object": "^1.0.1",
- "is-symbol": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/eventemitter3": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
- "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q=="
- },
- "node_modules/extend": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
- "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
- },
- "node_modules/extsprintf": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
- "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==",
- "engines": [
- "node >=0.6.0"
- ]
- },
- "node_modules/fast-deep-equal": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
- },
- "node_modules/fast-json-stable-stringify": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
- },
- "node_modules/file-type": {
- "version": "3.9.0",
- "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
- "integrity": "sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/for-each": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
- "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
- "dependencies": {
- "is-callable": "^1.1.3"
- }
- },
- "node_modules/forever-agent": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
- "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==",
- "engines": {
- "node": "*"
- }
- },
- "node_modules/form-data": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
- "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
- "dependencies": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.6",
- "mime-types": "^2.1.12"
- },
- "engines": {
- "node": ">= 0.12"
- }
- },
- "node_modules/function-bind": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
- },
- "node_modules/function.prototype.name": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz",
- "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==",
- "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"
- }
- },
- "node_modules/functions-have-names": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
- "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/get-intrinsic": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
- "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==",
- "dependencies": {
- "function-bind": "^1.1.1",
- "has": "^1.0.3",
- "has-proto": "^1.0.1",
- "has-symbols": "^1.0.3"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/get-symbol-description": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
- "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/getpass": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
- "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==",
- "dependencies": {
- "assert-plus": "^1.0.0"
- }
- },
- "node_modules/globalthis": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz",
- "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==",
- "dependencies": {
- "define-properties": "^1.1.3"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/gopd": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
- "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
- "dependencies": {
- "get-intrinsic": "^1.1.3"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/har-schema": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
- "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/har-validator": {
- "version": "5.1.5",
- "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
- "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
- "deprecated": "this library is no longer supported",
- "dependencies": {
- "ajv": "^6.12.3",
- "har-schema": "^2.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/has": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
- "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
- "dependencies": {
- "function-bind": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4.0"
- }
- },
- "node_modules/has-bigints": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
- "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-property-descriptors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
- "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
- "dependencies": {
- "get-intrinsic": "^1.1.1"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-proto": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
- "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-symbols": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
- "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-tostringtag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
- "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
- "dependencies": {
- "has-symbols": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/http-signature": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
- "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==",
- "dependencies": {
- "assert-plus": "^1.0.0",
- "jsprim": "^1.2.2",
- "sshpk": "^1.7.0"
- },
- "engines": {
- "node": ">=0.8",
- "npm": ">=1.3.7"
- }
- },
- "node_modules/inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
- },
- "node_modules/internal-slot": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz",
- "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==",
- "dependencies": {
- "get-intrinsic": "^1.2.0",
- "has": "^1.0.3",
- "side-channel": "^1.0.4"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/is-array-buffer": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz",
- "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.2.0",
- "is-typed-array": "^1.1.10"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-bigint": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
- "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
- "dependencies": {
- "has-bigints": "^1.0.1"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-boolean-object": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
- "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-callable": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
- "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-date-object": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
- "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
- "dependencies": {
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-negative-zero": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
- "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-number-object": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
- "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
- "dependencies": {
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-regex": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
- "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
- "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",
- "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
- "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==",
- "dependencies": {
- "call-bind": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-string": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
- "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
- "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",
- "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
- "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
- "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",
- "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz",
- "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==",
- "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-typedarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
- "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
- },
- "node_modules/is-weakref": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
- "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
- "dependencies": {
- "call-bind": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/isarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
- },
- "node_modules/isstream": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
- "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g=="
- },
- "node_modules/jsbn": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
- "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg=="
- },
- "node_modules/json-schema": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
- "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="
- },
- "node_modules/json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
- },
- "node_modules/json-stringify-safe": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
- "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="
- },
- "node_modules/jsprim": {
- "version": "1.4.2",
- "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
- "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==",
- "dependencies": {
- "assert-plus": "1.0.0",
- "extsprintf": "1.3.0",
- "json-schema": "0.4.0",
- "verror": "1.10.0"
- },
- "engines": {
- "node": ">=0.6.0"
- }
- },
- "node_modules/lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
- },
- "node_modules/mime": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
- "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
- "bin": {
- "mime": "cli.js"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/mime-types": {
- "version": "2.1.35",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
- "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "dependencies": {
- "mime-db": "1.52.0"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
- },
- "node_modules/node-telegram-bot-api": {
- "version": "0.61.0",
- "resolved": "https://registry.npmjs.org/node-telegram-bot-api/-/node-telegram-bot-api-0.61.0.tgz",
- "integrity": "sha512-BZXd8Bh2C5+uBEQuuI3FD7TFJF3alV+6oFQt8CNLx3ldX/hsd+NYyllTX+Y+5X0tG+xtcRQQjbfLgz/4sRvmBQ==",
- "dependencies": {
- "array.prototype.findindex": "^2.0.2",
- "bl": "^1.2.3",
- "debug": "^3.2.7",
- "eventemitter3": "^3.0.0",
- "file-type": "^3.9.0",
- "mime": "^1.6.0",
- "pump": "^2.0.0",
- "request": "^2.83.0",
- "request-promise": "^4.2.2"
- },
- "engines": {
- "node": ">=0.12"
- }
- },
- "node_modules/oauth-sign": {
- "version": "0.9.0",
- "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
- "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
- "engines": {
- "node": "*"
- }
- },
- "node_modules/object-inspect": {
- "version": "1.12.3",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
- "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/object-keys": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
- "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/object.assign": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz",
- "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==",
- "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/once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
- "dependencies": {
- "wrappy": "1"
- }
- },
- "node_modules/performance-now": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
- "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
- },
- "node_modules/process-nextick-args": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
- "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
- },
- "node_modules/psl": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
- "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag=="
- },
- "node_modules/pump": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
- "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
- "dependencies": {
- "end-of-stream": "^1.1.0",
- "once": "^1.3.1"
- }
- },
- "node_modules/punycode": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
- "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/qs": {
- "version": "6.5.3",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz",
- "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==",
- "engines": {
- "node": ">=0.6"
- }
- },
- "node_modules/readable-stream": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
- "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
- "dependencies": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.3",
- "isarray": "~1.0.0",
- "process-nextick-args": "~2.0.0",
- "safe-buffer": "~5.1.1",
- "string_decoder": "~1.1.1",
- "util-deprecate": "~1.0.1"
- }
- },
- "node_modules/readable-stream/node_modules/safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
- },
- "node_modules/regexp.prototype.flags": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz",
- "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.2.0",
- "functions-have-names": "^1.2.3"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/request": {
- "version": "2.88.2",
- "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
- "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
- "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142",
- "dependencies": {
- "aws-sign2": "~0.7.0",
- "aws4": "^1.8.0",
- "caseless": "~0.12.0",
- "combined-stream": "~1.0.6",
- "extend": "~3.0.2",
- "forever-agent": "~0.6.1",
- "form-data": "~2.3.2",
- "har-validator": "~5.1.3",
- "http-signature": "~1.2.0",
- "is-typedarray": "~1.0.0",
- "isstream": "~0.1.2",
- "json-stringify-safe": "~5.0.1",
- "mime-types": "~2.1.19",
- "oauth-sign": "~0.9.0",
- "performance-now": "^2.1.0",
- "qs": "~6.5.2",
- "safe-buffer": "^5.1.2",
- "tough-cookie": "~2.5.0",
- "tunnel-agent": "^0.6.0",
- "uuid": "^3.3.2"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/request-promise": {
- "version": "4.2.6",
- "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.6.tgz",
- "integrity": "sha512-HCHI3DJJUakkOr8fNoCc73E5nU5bqITjOYFMDrKHYOXWXrgD/SBaC7LjwuPymUprRyuF06UK7hd/lMHkmUXglQ==",
- "deprecated": "request-promise has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142",
- "dependencies": {
- "bluebird": "^3.5.0",
- "request-promise-core": "1.1.4",
- "stealthy-require": "^1.1.1",
- "tough-cookie": "^2.3.3"
- },
- "engines": {
- "node": ">=0.10.0"
- },
- "peerDependencies": {
- "request": "^2.34"
- }
- },
- "node_modules/request-promise-core": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz",
- "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==",
- "dependencies": {
- "lodash": "^4.17.19"
- },
- "engines": {
- "node": ">=0.10.0"
- },
- "peerDependencies": {
- "request": "^2.34"
- }
- },
- "node_modules/safe-buffer": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ]
- },
- "node_modules/safe-regex-test": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz",
- "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==",
- "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",
- "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
- },
- "node_modules/side-channel": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
- "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
- "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/sshpk": {
- "version": "1.17.0",
- "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz",
- "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==",
- "dependencies": {
- "asn1": "~0.2.3",
- "assert-plus": "^1.0.0",
- "bcrypt-pbkdf": "^1.0.0",
- "dashdash": "^1.12.0",
- "ecc-jsbn": "~0.1.1",
- "getpass": "^0.1.1",
- "jsbn": "~0.1.0",
- "safer-buffer": "^2.0.2",
- "tweetnacl": "~0.14.0"
- },
- "bin": {
- "sshpk-conv": "bin/sshpk-conv",
- "sshpk-sign": "bin/sshpk-sign",
- "sshpk-verify": "bin/sshpk-verify"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/stealthy-require": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
- "integrity": "sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "dependencies": {
- "safe-buffer": "~5.1.0"
- }
- },
- "node_modules/string_decoder/node_modules/safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
- },
- "node_modules/string.prototype.trim": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz",
- "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==",
- "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/string.prototype.trimend": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz",
- "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==",
- "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",
- "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz",
- "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==",
- "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/tough-cookie": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
- "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
- "dependencies": {
- "psl": "^1.1.28",
- "punycode": "^2.1.1"
- },
- "engines": {
- "node": ">=0.8"
- }
- },
- "node_modules/tunnel-agent": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
- "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
- "dependencies": {
- "safe-buffer": "^5.0.1"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/tweetnacl": {
- "version": "0.14.5",
- "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
- "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="
- },
- "node_modules/typed-array-length": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz",
- "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==",
- "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/unbox-primitive": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
- "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
- "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/uri-js": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
- "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "dependencies": {
- "punycode": "^2.1.0"
- }
- },
- "node_modules/util-deprecate": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
- },
- "node_modules/uuid": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
- "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
- "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
- "bin": {
- "uuid": "bin/uuid"
- }
- },
- "node_modules/verror": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
- "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==",
- "engines": [
- "node >=0.6.0"
- ],
- "dependencies": {
- "assert-plus": "^1.0.0",
- "core-util-is": "1.0.2",
- "extsprintf": "^1.2.0"
- }
- },
- "node_modules/verror/node_modules/core-util-is": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
- "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="
- },
- "node_modules/which-boxed-primitive": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
- "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
- "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",
- "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz",
- "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==",
- "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/wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
- }
- },
- "dependencies": {
- "@revanced-helper/helper-client": {
- "version": "file:../../../packages/client",
- "requires": {
- "bson": "^4.7.0"
- }
- },
- "ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "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"
- }
- },
- "array-buffer-byte-length": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz",
- "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==",
- "requires": {
- "call-bind": "^1.0.2",
- "is-array-buffer": "^3.0.1"
- }
- },
- "array.prototype.findindex": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/array.prototype.findindex/-/array.prototype.findindex-2.2.1.tgz",
- "integrity": "sha512-tMj4uTmGpaGUh4XFMUh3H7KYAIqlygrlXchOEVTiICbTwRwMhDqtzsOwvtI+WAf1GdjJBeIP3Bu92Qg0SnXdtA==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4",
- "es-shim-unscopables": "^1.0.0"
- }
- },
- "asn1": {
- "version": "0.2.6",
- "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
- "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
- "requires": {
- "safer-buffer": "~2.1.0"
- }
- },
- "assert-plus": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
- "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw=="
- },
- "asynckit": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
- },
- "available-typed-arrays": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
- "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw=="
- },
- "aws-sign2": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
- "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA=="
- },
- "aws4": {
- "version": "1.12.0",
- "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz",
- "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg=="
- },
- "bcrypt-pbkdf": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
- "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
- "requires": {
- "tweetnacl": "^0.14.3"
- }
- },
- "bl": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz",
- "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==",
- "requires": {
- "readable-stream": "^2.3.5",
- "safe-buffer": "^5.1.1"
- }
- },
- "bluebird": {
- "version": "3.7.2",
- "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
- "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
- },
- "call-bind": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
- "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
- "requires": {
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.0.2"
- }
- },
- "caseless": {
- "version": "0.12.0",
- "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
- "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw=="
- },
- "combined-stream": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
- "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
- "requires": {
- "delayed-stream": "~1.0.0"
- }
- },
- "core-util-is": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
- "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
- },
- "dashdash": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
- "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==",
- "requires": {
- "assert-plus": "^1.0.0"
- }
- },
- "debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "requires": {
- "ms": "^2.1.1"
- }
- },
- "define-properties": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz",
- "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==",
- "requires": {
- "has-property-descriptors": "^1.0.0",
- "object-keys": "^1.1.1"
- }
- },
- "delayed-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
- "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
- },
- "ecc-jsbn": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
- "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==",
- "requires": {
- "jsbn": "~0.1.0",
- "safer-buffer": "^2.1.0"
- }
- },
- "end-of-stream": {
- "version": "1.4.4",
- "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
- "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
- "requires": {
- "once": "^1.4.0"
- }
- },
- "es-abstract": {
- "version": "1.21.2",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz",
- "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==",
- "requires": {
- "array-buffer-byte-length": "^1.0.0",
- "available-typed-arrays": "^1.0.5",
- "call-bind": "^1.0.2",
- "es-set-tostringtag": "^2.0.1",
- "es-to-primitive": "^1.2.1",
- "function.prototype.name": "^1.1.5",
- "get-intrinsic": "^1.2.0",
- "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.5",
- "is-array-buffer": "^3.0.2",
- "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.3",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.4",
- "regexp.prototype.flags": "^1.4.3",
- "safe-regex-test": "^1.0.0",
- "string.prototype.trim": "^1.2.7",
- "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",
- "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz",
- "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==",
- "requires": {
- "get-intrinsic": "^1.1.3",
- "has": "^1.0.3",
- "has-tostringtag": "^1.0.0"
- }
- },
- "es-shim-unscopables": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz",
- "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==",
- "requires": {
- "has": "^1.0.3"
- }
- },
- "es-to-primitive": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
- "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
- "requires": {
- "is-callable": "^1.1.4",
- "is-date-object": "^1.0.1",
- "is-symbol": "^1.0.2"
- }
- },
- "eventemitter3": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
- "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q=="
- },
- "extend": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
- "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
- },
- "extsprintf": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
- "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g=="
- },
- "fast-deep-equal": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
- },
- "fast-json-stable-stringify": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
- },
- "file-type": {
- "version": "3.9.0",
- "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
- "integrity": "sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA=="
- },
- "for-each": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
- "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
- "requires": {
- "is-callable": "^1.1.3"
- }
- },
- "forever-agent": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
- "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw=="
- },
- "form-data": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
- "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
- "requires": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.6",
- "mime-types": "^2.1.12"
- }
- },
- "function-bind": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
- },
- "function.prototype.name": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz",
- "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==",
- "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",
- "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
- "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="
- },
- "get-intrinsic": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
- "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==",
- "requires": {
- "function-bind": "^1.1.1",
- "has": "^1.0.3",
- "has-proto": "^1.0.1",
- "has-symbols": "^1.0.3"
- }
- },
- "get-symbol-description": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
- "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==",
- "requires": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.1"
- }
- },
- "getpass": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
- "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==",
- "requires": {
- "assert-plus": "^1.0.0"
- }
- },
- "globalthis": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz",
- "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==",
- "requires": {
- "define-properties": "^1.1.3"
- }
- },
- "gopd": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
- "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
- "requires": {
- "get-intrinsic": "^1.1.3"
- }
- },
- "har-schema": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
- "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q=="
- },
- "har-validator": {
- "version": "5.1.5",
- "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
- "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
- "requires": {
- "ajv": "^6.12.3",
- "har-schema": "^2.0.0"
- }
- },
- "has": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
- "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
- "requires": {
- "function-bind": "^1.1.1"
- }
- },
- "has-bigints": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
- "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ=="
- },
- "has-property-descriptors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
- "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
- "requires": {
- "get-intrinsic": "^1.1.1"
- }
- },
- "has-proto": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
- "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg=="
- },
- "has-symbols": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
- "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
- },
- "has-tostringtag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
- "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
- "requires": {
- "has-symbols": "^1.0.2"
- }
- },
- "http-signature": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
- "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==",
- "requires": {
- "assert-plus": "^1.0.0",
- "jsprim": "^1.2.2",
- "sshpk": "^1.7.0"
- }
- },
- "inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
- },
- "internal-slot": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz",
- "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==",
- "requires": {
- "get-intrinsic": "^1.2.0",
- "has": "^1.0.3",
- "side-channel": "^1.0.4"
- }
- },
- "is-array-buffer": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz",
- "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==",
- "requires": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.2.0",
- "is-typed-array": "^1.1.10"
- }
- },
- "is-bigint": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
- "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
- "requires": {
- "has-bigints": "^1.0.1"
- }
- },
- "is-boolean-object": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
- "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
- "requires": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-callable": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
- "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="
- },
- "is-date-object": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
- "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
- "requires": {
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-negative-zero": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
- "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA=="
- },
- "is-number-object": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
- "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
- "requires": {
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-regex": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
- "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
- "requires": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-shared-array-buffer": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
- "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==",
- "requires": {
- "call-bind": "^1.0.2"
- }
- },
- "is-string": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
- "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
- "requires": {
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-symbol": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
- "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
- "requires": {
- "has-symbols": "^1.0.2"
- }
- },
- "is-typed-array": {
- "version": "1.1.10",
- "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz",
- "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==",
- "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"
- }
- },
- "is-typedarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
- "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
- },
- "is-weakref": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
- "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
- "requires": {
- "call-bind": "^1.0.2"
- }
- },
- "isarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
- },
- "isstream": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
- "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g=="
- },
- "jsbn": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
- "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg=="
- },
- "json-schema": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
- "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="
- },
- "json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
- },
- "json-stringify-safe": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
- "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="
- },
- "jsprim": {
- "version": "1.4.2",
- "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
- "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==",
- "requires": {
- "assert-plus": "1.0.0",
- "extsprintf": "1.3.0",
- "json-schema": "0.4.0",
- "verror": "1.10.0"
- }
- },
- "lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
- },
- "mime": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
- "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
- },
- "mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
- },
- "mime-types": {
- "version": "2.1.35",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
- "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "requires": {
- "mime-db": "1.52.0"
- }
- },
- "ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
- },
- "node-telegram-bot-api": {
- "version": "0.61.0",
- "resolved": "https://registry.npmjs.org/node-telegram-bot-api/-/node-telegram-bot-api-0.61.0.tgz",
- "integrity": "sha512-BZXd8Bh2C5+uBEQuuI3FD7TFJF3alV+6oFQt8CNLx3ldX/hsd+NYyllTX+Y+5X0tG+xtcRQQjbfLgz/4sRvmBQ==",
- "requires": {
- "array.prototype.findindex": "^2.0.2",
- "bl": "^1.2.3",
- "debug": "^3.2.7",
- "eventemitter3": "^3.0.0",
- "file-type": "^3.9.0",
- "mime": "^1.6.0",
- "pump": "^2.0.0",
- "request": "^2.83.0",
- "request-promise": "^4.2.2"
- }
- },
- "oauth-sign": {
- "version": "0.9.0",
- "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
- "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
- },
- "object-inspect": {
- "version": "1.12.3",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
- "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g=="
- },
- "object-keys": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
- "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="
- },
- "object.assign": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz",
- "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "has-symbols": "^1.0.3",
- "object-keys": "^1.1.1"
- }
- },
- "once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
- "requires": {
- "wrappy": "1"
- }
- },
- "performance-now": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
- "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
- },
- "process-nextick-args": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
- "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
- },
- "psl": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
- "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag=="
- },
- "pump": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
- "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
- "requires": {
- "end-of-stream": "^1.1.0",
- "once": "^1.3.1"
- }
- },
- "punycode": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
- "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA=="
- },
- "qs": {
- "version": "6.5.3",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz",
- "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA=="
- },
- "readable-stream": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
- "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
- "requires": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.3",
- "isarray": "~1.0.0",
- "process-nextick-args": "~2.0.0",
- "safe-buffer": "~5.1.1",
- "string_decoder": "~1.1.1",
- "util-deprecate": "~1.0.1"
- },
- "dependencies": {
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
- }
- }
- },
- "regexp.prototype.flags": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz",
- "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.2.0",
- "functions-have-names": "^1.2.3"
- }
- },
- "request": {
- "version": "2.88.2",
- "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
- "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
- "requires": {
- "aws-sign2": "~0.7.0",
- "aws4": "^1.8.0",
- "caseless": "~0.12.0",
- "combined-stream": "~1.0.6",
- "extend": "~3.0.2",
- "forever-agent": "~0.6.1",
- "form-data": "~2.3.2",
- "har-validator": "~5.1.3",
- "http-signature": "~1.2.0",
- "is-typedarray": "~1.0.0",
- "isstream": "~0.1.2",
- "json-stringify-safe": "~5.0.1",
- "mime-types": "~2.1.19",
- "oauth-sign": "~0.9.0",
- "performance-now": "^2.1.0",
- "qs": "~6.5.2",
- "safe-buffer": "^5.1.2",
- "tough-cookie": "~2.5.0",
- "tunnel-agent": "^0.6.0",
- "uuid": "^3.3.2"
- }
- },
- "request-promise": {
- "version": "4.2.6",
- "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.6.tgz",
- "integrity": "sha512-HCHI3DJJUakkOr8fNoCc73E5nU5bqITjOYFMDrKHYOXWXrgD/SBaC7LjwuPymUprRyuF06UK7hd/lMHkmUXglQ==",
- "requires": {
- "bluebird": "^3.5.0",
- "request-promise-core": "1.1.4",
- "stealthy-require": "^1.1.1",
- "tough-cookie": "^2.3.3"
- }
- },
- "request-promise-core": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz",
- "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==",
- "requires": {
- "lodash": "^4.17.19"
- }
- },
- "safe-buffer": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
- },
- "safe-regex-test": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz",
- "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==",
- "requires": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.3",
- "is-regex": "^1.1.4"
- }
- },
- "safer-buffer": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
- },
- "side-channel": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
- "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
- "requires": {
- "call-bind": "^1.0.0",
- "get-intrinsic": "^1.0.2",
- "object-inspect": "^1.9.0"
- }
- },
- "sshpk": {
- "version": "1.17.0",
- "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz",
- "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==",
- "requires": {
- "asn1": "~0.2.3",
- "assert-plus": "^1.0.0",
- "bcrypt-pbkdf": "^1.0.0",
- "dashdash": "^1.12.0",
- "ecc-jsbn": "~0.1.1",
- "getpass": "^0.1.1",
- "jsbn": "~0.1.0",
- "safer-buffer": "^2.0.2",
- "tweetnacl": "~0.14.0"
- }
- },
- "stealthy-require": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
- "integrity": "sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g=="
- },
- "string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "requires": {
- "safe-buffer": "~5.1.0"
- },
- "dependencies": {
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
- }
- }
- },
- "string.prototype.trim": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz",
- "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4"
- }
- },
- "string.prototype.trimend": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz",
- "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4"
- }
- },
- "string.prototype.trimstart": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz",
- "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4"
- }
- },
- "tough-cookie": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
- "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
- "requires": {
- "psl": "^1.1.28",
- "punycode": "^2.1.1"
- }
- },
- "tunnel-agent": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
- "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
- "requires": {
- "safe-buffer": "^5.0.1"
- }
- },
- "tweetnacl": {
- "version": "0.14.5",
- "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
- "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="
- },
- "typed-array-length": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz",
- "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==",
- "requires": {
- "call-bind": "^1.0.2",
- "for-each": "^0.3.3",
- "is-typed-array": "^1.1.9"
- }
- },
- "unbox-primitive": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
- "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
- "requires": {
- "call-bind": "^1.0.2",
- "has-bigints": "^1.0.2",
- "has-symbols": "^1.0.3",
- "which-boxed-primitive": "^1.0.2"
- }
- },
- "uri-js": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
- "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "requires": {
- "punycode": "^2.1.0"
- }
- },
- "util-deprecate": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
- },
- "uuid": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
- "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
- },
- "verror": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
- "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==",
- "requires": {
- "assert-plus": "^1.0.0",
- "core-util-is": "1.0.2",
- "extsprintf": "^1.2.0"
- },
- "dependencies": {
- "core-util-is": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
- "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="
- }
- }
- },
- "which-boxed-primitive": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
- "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
- "requires": {
- "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"
- }
- },
- "which-typed-array": {
- "version": "1.1.9",
- "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz",
- "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==",
- "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",
- "is-typed-array": "^1.1.10"
- }
- },
- "wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
- }
- }
-}
diff --git a/apps/bot-telegram/src/package.json b/apps/bot-telegram/src/package.json
deleted file mode 100644
index 6cc77c6..0000000
--- a/apps/bot-telegram/src/package.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "name": "bot-telegram",
- "version": "1.0.0",
- "description": "",
- "main": "index.js",
- "type": "module",
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
- },
- "keywords": [],
- "author": "Reis Can",
- "license": "GPL-3.0-or-later",
- "dependencies": {
- "@revanced-helper/helper-client": "file:../../../packages/client",
- "node-telegram-bot-api": "^0.61.0"
- }
-}
diff --git a/apps/server/src/PROTOCOL.md b/apps/server/src/PROTOCOL.md
deleted file mode 100644
index 4cfbdd4..0000000
--- a/apps/server/src/PROTOCOL.md
+++ /dev/null
@@ -1,64 +0,0 @@
-# Server Protocol
-
-The server uses TCP for connection and BSON for messages, so you need to serialize and deserialize the messages.
-
-## AI
-
-Sending the server this JSON (BSON) will send you back the AI predictions.
-
-```json
-{
- "op": 1,
- "id": "String",
- "text": "How do i download ReVanced?"
-}
-```
-
-And the server would return something like this:
-
-```json
-{
- "op": 2,
- "id": "String",
- "response": [
- {
- "confidence": 0.99,
- "name": "revanced_download"
- }
- ]
-}
-```
-
-### Training the AI
-
-To train the AI, send the server a JSON (BSON) like this:
-
-```json
-{
- "op": 3,
- "label": "revanced_download",
- "text": "how to download revanced"
-}
-```
-
-## OCR
-
-Sending the server this JSON (BSON) will send you back the read text.
-
-```json
-{
- "op": 5,
- "id": "String",
- "url": "https://cdn.discordapp.com/attachments/1033338556493606963/1033338557231796224/Screenshot_20221022-121318.jpg"
-}
-```
-
-And the server would return something like this:
-
-```json
-{
- "op": 6,
- "id": "String",
- "ocrText": "..."
-}
-```
diff --git a/apps/server/src/config.example.json b/apps/server/src/config.example.json
deleted file mode 100644
index cdd14d0..0000000
--- a/apps/server/src/config.example.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "regexSupport": false,
- "regexResponses": [
- {
- "label": "videobuffer",
- "regex": "insert regex here"
- }
- ]
-}
\ No newline at end of file
diff --git a/apps/server/src/events/index.js b/apps/server/src/events/index.js
deleted file mode 100644
index 4cc4c44..0000000
--- a/apps/server/src/events/index.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import runAI from './runAI.js';
-import runOCR from './runOCR.js';
-import trainAI from './trainAI.js';
-
-export { runAI, runOCR, trainAI };
\ No newline at end of file
diff --git a/apps/server/src/events/runAI.js b/apps/server/src/events/runAI.js
deleted file mode 100644
index 85b3772..0000000
--- a/apps/server/src/events/runAI.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import { serialize } from 'bson';
-
-export default async function runAI(client, data, config) {
- if (config.regexSupport) {
- for (const reply of config.regexResponses) {
- if (new RegExp(reply.regex).test(data.text)) {
- client.write(
- serialize({
- op: 2,
- id: data.id,
- response: [
- {
- confidence: 1,
- name: reply.label
- }
- ]
- })
- );
- return;
- }
- }
- }
- const witAIReq = await fetch(
- `https://api.wit.ai/message?v=20230215&q=${encodeURI(data.text)}`,
- {
- headers: {
- authorization: `Bearer ${process.env.WIT_AI_TOKEN}`
- }
- }
- );
-
- const response = await witAIReq.json();
-
- client.write(
- serialize({
- op: 2,
- id: data.id,
- response: response.intents
- })
- );
-
- return;
-}
\ No newline at end of file
diff --git a/apps/server/src/events/runOCR.js b/apps/server/src/events/runOCR.js
deleted file mode 100644
index 0f22ad8..0000000
--- a/apps/server/src/events/runOCR.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import { createWorker } from 'tesseract.js';
-import { serialize } from 'bson';
-import EventEmitter from 'node:events';
-
-const worker = await createWorker();
-await worker.loadLanguage('eng');
-await worker.initialize('eng');
-
-async function recognize({ client, data }) {
- const { data: { text } } = await worker.recognize(data.url);
-
- client.write(
- serialize({
- op: 6,
- id: data.id,
- ocrText: text
- })
- );
-}
-
-class Queue extends EventEmitter {
- constructor() {
- super();
- this.isRunning = false;
- this.items = []
- }
-
- push(item) {
- this.items.push(item);
- this.emit('item', item)
- }
-
- shift() {
- return this.items.shift();
- }
-
-}
-
-const queue = new Queue();
-
-queue.on('item', async ({ client, data }) => {
- if (!queue.isRunning) {
- queue.isRunning = true;
- await recognize(queue.items.shift());
- queue.isRunning = false;
- queue.emit('finished');
- }
-});
-
-queue.on('finished', async () => {
- if (queue.items.length !== 0) {
- queue.isRunning = true;
- await recognize(queue.items.shift());
- queue.isRunning = false;
- queue.emit('finished');
- }
-});
-
-export default async function runOCR(client, data) {
- queue.push({ client, data });
-}
diff --git a/apps/server/src/events/trainAI.js b/apps/server/src/events/trainAI.js
deleted file mode 100644
index a3904ad..0000000
--- a/apps/server/src/events/trainAI.js
+++ /dev/null
@@ -1,17 +0,0 @@
-export default async function trainAI(data) {
- fetch('https://api.wit.ai/utterances', {
- headers: {
- authorization: `Bearer ${process.env.WIT_AI_TOKEN}`
- },
- body: JSON.stringify([
- {
- text: data.text,
- intent: data.label,
- entities: [],
- traits: []
- }
- ]),
- method: 'POST'
- });
- return;
-}
diff --git a/apps/server/src/index.js b/apps/server/src/index.js
deleted file mode 100644
index 1e40d87..0000000
--- a/apps/server/src/index.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import { createServer } from 'node:net';
-import { deserialize } from 'bson';
-import { runAI, runOCR, trainAI } from './events/index.js';
-import Config from './config.json' assert { type: 'json' };
-
-const server = createServer(async (client) => {
- client.on('data', async (data) => {
- const eventData = deserialize(data, {
- allowObjectSmallerThanBufferSize: true
- });
-
- switch (eventData.op) {
- case 1: {
- runAI(client, eventData, Config);
- break;
- }
-
- case 3: {
- trainAI(eventData);
- break;
- }
-
- case 5: {
- await runOCR(client, eventData);
- break;
- }
- }
- });
-});
-
-server.listen(process.env.PORT || 3000);
diff --git a/apps/server/src/package-lock.json b/apps/server/src/package-lock.json
deleted file mode 100644
index 4d27871..0000000
--- a/apps/server/src/package-lock.json
+++ /dev/null
@@ -1,228 +0,0 @@
-{
- "name": "server",
- "version": "1.0.0",
- "lockfileVersion": 2,
- "requires": true,
- "packages": {
- "": {
- "name": "server",
- "version": "1.0.0",
- "license": "GPL-3.0-or-later",
- "dependencies": {
- "bson": "^5.3.0",
- "tesseract.js": "^4.1.0"
- }
- },
- "node_modules/bmp-js": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz",
- "integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw=="
- },
- "node_modules/bson": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/bson/-/bson-5.3.0.tgz",
- "integrity": "sha512-ukmCZMneMlaC5ebPHXIkP8YJzNl5DC41N5MAIvKDqLggdao342t4McltoJBQfQya/nHBWAcSsYRqlXPoQkTJag==",
- "engines": {
- "node": ">=14.20.1"
- }
- },
- "node_modules/idb-keyval": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz",
- "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg=="
- },
- "node_modules/is-electron": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/is-electron/-/is-electron-2.2.2.tgz",
- "integrity": "sha512-FO/Rhvz5tuw4MCWkpMzHFKWD2LsfHzIb7i6MdPYZ/KW7AlxawyLkqdy+jPZP1WubqEADE3O4FUENlJHDfQASRg=="
- },
- "node_modules/is-url": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz",
- "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww=="
- },
- "node_modules/node-fetch": {
- "version": "2.6.11",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz",
- "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==",
- "dependencies": {
- "whatwg-url": "^5.0.0"
- },
- "engines": {
- "node": "4.x || >=6.0.0"
- },
- "peerDependencies": {
- "encoding": "^0.1.0"
- },
- "peerDependenciesMeta": {
- "encoding": {
- "optional": true
- }
- }
- },
- "node_modules/opencollective-postinstall": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
- "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==",
- "bin": {
- "opencollective-postinstall": "index.js"
- }
- },
- "node_modules/regenerator-runtime": {
- "version": "0.13.11",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
- "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
- },
- "node_modules/tesseract.js": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/tesseract.js/-/tesseract.js-4.1.0.tgz",
- "integrity": "sha512-sCfWJtei6Ykc7uLiWs5H4IKDAhwsMauEVDwUiSkEpzMo4kH+7n8QDBPPNRtGJoZ4NJBf1WSlcbU+Puf64GjOfw==",
- "hasInstallScript": true,
- "dependencies": {
- "bmp-js": "^0.1.0",
- "idb-keyval": "^6.2.0",
- "is-electron": "^2.2.2",
- "is-url": "^1.2.4",
- "node-fetch": "^2.6.9",
- "opencollective-postinstall": "^2.0.3",
- "regenerator-runtime": "^0.13.3",
- "tesseract.js-core": "^4.0.4",
- "wasm-feature-detect": "^1.2.11",
- "zlibjs": "^0.3.1"
- }
- },
- "node_modules/tesseract.js-core": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/tesseract.js-core/-/tesseract.js-core-4.0.4.tgz",
- "integrity": "sha512-MJ+vtktjAaT0681uPl6TDUPhbRbpD/S9emko5rtorgHRZpQo7R3BG7h+3pVHgn1KjfNf1bvnx4B7KxEK8YKqpg=="
- },
- "node_modules/tr46": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
- },
- "node_modules/wasm-feature-detect": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.5.1.tgz",
- "integrity": "sha512-GHr23qmuehNXHY4902/hJ6EV5sUANIJC3R/yMfQ7hWDg3nfhlcJfnIL96R2ohpIwa62araN6aN4bLzzzq5GXkg=="
- },
- "node_modules/webidl-conversions": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
- "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
- },
- "node_modules/whatwg-url": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
- "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
- "dependencies": {
- "tr46": "~0.0.3",
- "webidl-conversions": "^3.0.0"
- }
- },
- "node_modules/zlibjs": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/zlibjs/-/zlibjs-0.3.1.tgz",
- "integrity": "sha512-+J9RrgTKOmlxFSDHo0pI1xM6BLVUv+o0ZT9ANtCxGkjIVCCUdx9alUF8Gm+dGLKbkkkidWIHFDZHDMpfITt4+w==",
- "engines": {
- "node": "*"
- }
- }
- },
- "dependencies": {
- "bmp-js": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz",
- "integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw=="
- },
- "bson": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/bson/-/bson-5.3.0.tgz",
- "integrity": "sha512-ukmCZMneMlaC5ebPHXIkP8YJzNl5DC41N5MAIvKDqLggdao342t4McltoJBQfQya/nHBWAcSsYRqlXPoQkTJag=="
- },
- "idb-keyval": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz",
- "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg=="
- },
- "is-electron": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/is-electron/-/is-electron-2.2.2.tgz",
- "integrity": "sha512-FO/Rhvz5tuw4MCWkpMzHFKWD2LsfHzIb7i6MdPYZ/KW7AlxawyLkqdy+jPZP1WubqEADE3O4FUENlJHDfQASRg=="
- },
- "is-url": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz",
- "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww=="
- },
- "node-fetch": {
- "version": "2.6.11",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz",
- "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==",
- "requires": {
- "whatwg-url": "^5.0.0"
- }
- },
- "opencollective-postinstall": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
- "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q=="
- },
- "regenerator-runtime": {
- "version": "0.13.11",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
- "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
- },
- "tesseract.js": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/tesseract.js/-/tesseract.js-4.1.0.tgz",
- "integrity": "sha512-sCfWJtei6Ykc7uLiWs5H4IKDAhwsMauEVDwUiSkEpzMo4kH+7n8QDBPPNRtGJoZ4NJBf1WSlcbU+Puf64GjOfw==",
- "requires": {
- "bmp-js": "^0.1.0",
- "idb-keyval": "^6.2.0",
- "is-electron": "^2.2.2",
- "is-url": "^1.2.4",
- "node-fetch": "^2.6.9",
- "opencollective-postinstall": "^2.0.3",
- "regenerator-runtime": "^0.13.3",
- "tesseract.js-core": "^4.0.4",
- "wasm-feature-detect": "^1.2.11",
- "zlibjs": "^0.3.1"
- }
- },
- "tesseract.js-core": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/tesseract.js-core/-/tesseract.js-core-4.0.4.tgz",
- "integrity": "sha512-MJ+vtktjAaT0681uPl6TDUPhbRbpD/S9emko5rtorgHRZpQo7R3BG7h+3pVHgn1KjfNf1bvnx4B7KxEK8YKqpg=="
- },
- "tr46": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
- },
- "wasm-feature-detect": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.5.1.tgz",
- "integrity": "sha512-GHr23qmuehNXHY4902/hJ6EV5sUANIJC3R/yMfQ7hWDg3nfhlcJfnIL96R2ohpIwa62araN6aN4bLzzzq5GXkg=="
- },
- "webidl-conversions": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
- "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
- },
- "whatwg-url": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
- "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
- "requires": {
- "tr46": "~0.0.3",
- "webidl-conversions": "^3.0.0"
- }
- },
- "zlibjs": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/zlibjs/-/zlibjs-0.3.1.tgz",
- "integrity": "sha512-+J9RrgTKOmlxFSDHo0pI1xM6BLVUv+o0ZT9ANtCxGkjIVCCUdx9alUF8Gm+dGLKbkkkidWIHFDZHDMpfITt4+w=="
- }
- }
-}
diff --git a/apps/server/src/package.json b/apps/server/src/package.json
deleted file mode 100644
index 8468519..0000000
--- a/apps/server/src/package.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "name": "server",
- "version": "1.0.0",
- "description": "",
- "main": "index.js",
- "type": "module",
- "keywords": [],
- "author": "Reis Can",
- "license": "GPL-3.0-or-later",
- "dependencies": {
- "bson": "^5.3.0",
- "tesseract.js": "^4.1.0"
- }
-}
diff --git a/assets/revanced-headline/revanced-headline-vertical-dark.svg b/assets/revanced-headline/revanced-headline-vertical-dark.svg
new file mode 100644
index 0000000..a59bfb5
--- /dev/null
+++ b/assets/revanced-headline/revanced-headline-vertical-dark.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/revanced-headline/revanced-headline-vertical-light.svg b/assets/revanced-headline/revanced-headline-vertical-light.svg
new file mode 100644
index 0000000..3c5eecc
--- /dev/null
+++ b/assets/revanced-headline/revanced-headline-vertical-light.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/revanced-logo/revanced-logo-round.svg b/assets/revanced-logo/revanced-logo-round.svg
new file mode 100644
index 0000000..db84091
--- /dev/null
+++ b/assets/revanced-logo/revanced-logo-round.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/biome.json b/biome.json
new file mode 100644
index 0000000..7b175a7
--- /dev/null
+++ b/biome.json
@@ -0,0 +1,60 @@
+{
+ "$schema": "https://biomejs.dev/schemas/1.8.2/schema.json",
+ "organizeImports": {
+ "enabled": true
+ },
+ "linter": {
+ "enabled": true,
+ "rules": {
+ "recommended": true,
+ "complexity": {
+ "useLiteralKeys": {
+ "level": "off"
+ }
+ },
+ "style": {
+ "noNonNullAssertion": {
+ "level": "off"
+ },
+ "useEnumInitializers": {
+ "level": "off"
+ },
+ "useNodejsImportProtocol": {
+ "level": "off"
+ },
+ "useNumberNamespace": {
+ "level": "off"
+ }
+ }
+ }
+ },
+ "json": {
+ "formatter": {
+ "enabled": true,
+ "indentStyle": "space",
+ "indentWidth": 2
+ },
+ "parser": {
+ "allowComments": true
+ }
+ },
+ "javascript": {
+ "formatter": {
+ "enabled": true,
+ "lineEnding": "crlf",
+ "arrowParentheses": "asNeeded",
+ "indentStyle": "space",
+ "indentWidth": 4,
+ "lineWidth": 120,
+ "quoteProperties": "asNeeded",
+ "quoteStyle": "single",
+ "semicolons": "asNeeded",
+ "trailingCommas": "all"
+ }
+ },
+ "files": {
+ "ignoreUnknown": true,
+ "include": ["*.js", "*.json", "*.ts"],
+ "ignore": ["dist/**/*", "node_modules/**/*"]
+ }
+}
diff --git a/bots/discord/.env.example b/bots/discord/.env.example
new file mode 100644
index 0000000..8685374
--- /dev/null
+++ b/bots/discord/.env.example
@@ -0,0 +1,2 @@
+DISCORD_TOKEN="YOUR-TOKEN-HERE"
+DATABASE_PATH=./db.sqlite3
\ No newline at end of file
diff --git a/bots/discord/.gitignore b/bots/discord/.gitignore
new file mode 100644
index 0000000..130f357
--- /dev/null
+++ b/bots/discord/.gitignore
@@ -0,0 +1,185 @@
+# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
+
+# Logs
+
+logs
+_.log
+npm-debug.log_
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+.pnpm-debug.log*
+
+# Caches
+
+.cache
+
+# Diagnostic reports (https://nodejs.org/api/report.html)
+
+report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
+
+# Runtime data
+
+pids
+_.pid
+_.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+
+lib-cov
+
+# Coverage directory used by tools like istanbul
+
+coverage
+*.lcov
+
+# nyc test coverage
+
+.nyc_output
+
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
+
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+
+bower_components
+
+# node-waf configuration
+
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+
+build/Release
+
+# Dependency directories
+
+node_modules/
+jspm_packages/
+
+# Snowpack dependency directory (https://snowpack.dev/)
+
+web_modules/
+
+# TypeScript cache
+
+*.tsbuildinfo
+
+# Optional npm cache directory
+
+.npm
+
+# Optional eslint cache
+
+.eslintcache
+
+# Optional stylelint cache
+
+.stylelintcache
+
+# Microbundle cache
+
+.rpt2_cache/
+.rts2_cache_cjs/
+.rts2_cache_es/
+.rts2_cache_umd/
+
+# Optional REPL history
+
+.node_repl_history
+
+# Output of 'npm pack'
+
+*.tgz
+
+# Yarn Integrity file
+
+.yarn-integrity
+
+# dotenv environment variable files
+
+.env
+.env.development.local
+.env.test.local
+.env.production.local
+.env.local
+
+# parcel-bundler cache (https://parceljs.org/)
+
+.parcel-cache
+
+# Next.js build output
+
+.next
+out
+
+# Nuxt.js build / generate output
+
+.nuxt
+dist
+
+# Gatsby files
+
+# Comment in the public line in if your project uses Gatsby and not Next.js
+
+# https://nextjs.org/blog/next-9-1#public-directory-support
+
+# public
+
+# vuepress build output
+
+.vuepress/dist
+
+# vuepress v2.x temp and cache directory
+
+.temp
+
+# Docusaurus cache and generated files
+
+.docusaurus
+
+# Serverless directories
+
+.serverless/
+
+# FuseBox cache
+
+.fusebox/
+
+# DynamoDB Local files
+
+.dynamodb/
+
+# TernJS port file
+
+.tern-port
+
+# Stores VSCode versions used for testing VSCode extensions
+
+.vscode-test
+
+# yarn v2
+
+.yarn/cache
+.yarn/unplugged
+.yarn/build-state.yml
+.yarn/install-state.gz
+.pnp.*
+
+# IntelliJ based IDEs
+.idea
+
+# Finder (MacOS) folder config
+.DS_Store
+
+# DB
+*.db
+*.sqlite
+*.sqlite3
+.drizzle
+
+# Auto-generated files
+src/commands/index.ts
+src/events/*/index.ts
\ No newline at end of file
diff --git a/bots/discord/.releaserc.js b/bots/discord/.releaserc.js
new file mode 100644
index 0000000..693e211
--- /dev/null
+++ b/bots/discord/.releaserc.js
@@ -0,0 +1,32 @@
+import defineSubprojectReleaseConfig from '../../semantic-release-config.js'
+
+export default defineSubprojectReleaseConfig({
+ plugins:
+ process.env.RELEASE_WORKFLOW_STEP === 'publish'
+ ? [
+ [
+ '@semantic-release/exec',
+ {
+ publishCmd: 'bun run scripts/trigger-portainer-webhook.ts',
+ },
+ ],
+ ]
+ : [
+ [
+ '@codedependant/semantic-release-docker',
+ {
+ dockerImage: 'revanced-bot-discord',
+ dockerRegistry: 'ghcr.io',
+ dockerProject: 'revanced',
+ dockerContext: '../..',
+ dockerPlatform: ['linux/amd64', 'linux/arm64'],
+ dockerBuildQuiet: false,
+ dockerTags: [
+ '{{#if prerelease.[0]}}dev{{else}}main{{/if}}',
+ '{{#unless prerelease.[0]}}latest{{/unless}}',
+ '{{version}}',
+ ],
+ },
+ ],
+ ],
+})
diff --git a/bots/discord/CHANGELOG.md b/bots/discord/CHANGELOG.md
new file mode 100644
index 0000000..7dc8f82
--- /dev/null
+++ b/bots/discord/CHANGELOG.md
@@ -0,0 +1,424 @@
+# @revanced/discord-bot [1.0.0-dev.38](https://github.com/revanced/revanced-bots/compare/@revanced/discord-bot@1.0.0-dev.37...@revanced/discord-bot@1.0.0-dev.38) (2025-04-04)
+
+
+### Bug Fixes
+
+* run projects with `--bun` ([bb2182e](https://github.com/revanced/revanced-bots/commit/bb2182e707fa40c555d56138972eeea28f1b3cf9))
+
+# @revanced/discord-bot [1.0.0-dev.37](https://github.com/revanced/revanced-bots/compare/@revanced/discord-bot@1.0.0-dev.36...@revanced/discord-bot@1.0.0-dev.37) (2025-03-08)
+
+
+### Bug Fixes
+
+* **bots/discord/utils/duration:** fix specified default unit not working ([d138af4](https://github.com/revanced/revanced-bots/commit/d138af46d1f25a11b6f8ab3790ecaa70b1d716a9))
+
+# @revanced/discord-bot [1.0.0-dev.36](https://github.com/revanced/revanced-bots/compare/@revanced/discord-bot@1.0.0-dev.35...@revanced/discord-bot@1.0.0-dev.36) (2025-03-03)
+
+
+### Bug Fixes
+
+* **bots/discord/scripts/build:** check if dist dir exists before cleaning ([c06033e](https://github.com/revanced/revanced-bots/commit/c06033e5730f82438e8052b9b519a8f8e2d25437))
+* **bots/discord/utils/duration:** make second the default unit ([5d1af3c](https://github.com/revanced/revanced-bots/commit/5d1af3c31c3379b6a13684dfb07583737908c8aa))
+* **bots/discord:** add GuildMember partial ([8e3946a](https://github.com/revanced/revanced-bots/commit/8e3946a66602838715787090008c7bfaf72b67e9))
+* **bots/discord:** decrease length of an option in `ban` command ([22d3eea](https://github.com/revanced/revanced-bots/commit/22d3eea88d532792c1237d1a1ab18bc02e57816a))
+* **bots/discord:** delete expired appliedPresets entries after unapplying ([14c98e8](https://github.com/revanced/revanced-bots/commit/14c98e87df1ec4fd762bbc48ca4c06470cb110a2))
+* fix typings and formatting ([479812e](https://github.com/revanced/revanced-bots/commit/479812e199b52cdb295a5746e0767306afab3413))
+* update repo url ([a21aa34](https://github.com/revanced/revanced-bots/commit/a21aa348d7f32cd0ee65b371e9594520c0a9d3f1))
+
+
+### Features
+
+* **bots/discord:** add more month aliases to duration parser ([c2009ca](https://github.com/revanced/revanced-bots/commit/c2009ca6d42e4387bc5f375d76ecf72991b7fe32))
+
+# @revanced/discord-bot [1.0.0-dev.35](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.34...@revanced/discord-bot@1.0.0-dev.35) (2024-10-17)
+
+
+### Bug Fixes
+
+* **bots/discord:** fix freeze on prod builds ([8efb549](https://github.com/revanced/revanced-helper/commit/8efb549453a04fab1ac6414a7f7f8bf702df3c93))
+
+# @revanced/discord-bot [1.0.0-dev.34](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.33...@revanced/discord-bot@1.0.0-dev.34) (2024-10-17)
+
+
+### Bug Fixes
+
+* **bots/discord:** attempt to fix stuck sticky message timeouts ([3ed5bd1](https://github.com/revanced/revanced-helper/commit/3ed5bd11acc3b4fbd57b0d632c68eb9f77365b8a))
+* **bots/discord:** fix reload not working ([11582d5](https://github.com/revanced/revanced-helper/commit/11582d50345cae9fb645a65ca4e621596de6a408))
+
+
+### Features
+
+* **bots/discord:** add default durations for moderation commands ([27d3b39](https://github.com/revanced/revanced-helper/commit/27d3b392092141a1e3b4b0298131ff7817458dc1))
+* **bots/discord:** cure on every event ([8ff6086](https://github.com/revanced/revanced-helper/commit/8ff6086028132cc4b49ee60846e8d6ef909f5a89))
+
+# @revanced/discord-bot [1.0.0-dev.33](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.32...@revanced/discord-bot@1.0.0-dev.33) (2024-09-25)
+
+
+### Features
+
+* **bots/discord:** add trigger to context for eval ([b5f4097](https://github.com/revanced/revanced-helper/commit/b5f40975386677ffff343c42f8ffac21f847a0b7))
+
+# @revanced/discord-bot [1.0.0-dev.32](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.31...@revanced/discord-bot@1.0.0-dev.32) (2024-09-25)
+
+
+### Bug Fixes
+
+* **bots/discord:** contextify object before sandboxing ([062735f](https://github.com/revanced/revanced-helper/commit/062735f6d552890404d6192244c51a11b0709580))
+
+# @revanced/discord-bot [1.0.0-dev.31](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.30...@revanced/discord-bot@1.0.0-dev.31) (2024-09-25)
+
+
+### Bug Fixes
+
+* **bots/discord:** persist changes in context for eval command ([5b4965d](https://github.com/revanced/revanced-helper/commit/5b4965dcc7285676b2b3b6756c249bd56eaf8485))
+
+# @revanced/discord-bot [1.0.0-dev.30](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.29...@revanced/discord-bot@1.0.0-dev.30) (2024-09-24)
+
+
+### Features
+
+* **bots/discord:** improve admin commands ([0346741](https://github.com/revanced/revanced-helper/commit/03467411882b8598e2c06f389a09ef2e201bb43f))
+
+# @revanced/discord-bot [1.0.0-dev.29](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.28...@revanced/discord-bot@1.0.0-dev.29) (2024-09-21)
+
+
+### Bug Fixes
+
+* **bots/discord:** fix get response logic ([3261294](https://github.com/revanced/revanced-helper/commit/3261294822b0a9faec094536ed5be2d3e1d5e17b))
+
+# @revanced/discord-bot [1.0.0-dev.28](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.27...@revanced/discord-bot@1.0.0-dev.28) (2024-09-20)
+
+
+### Bug Fixes
+
+* **bots/discord:** don't refresh timer if force timer is active for sticky messages ([4abac0c](https://github.com/revanced/revanced-helper/commit/4abac0c890c0548e14cb56723cae919353a8e726))
+* **bots/discord:** filter out text triggers correctly from image-only scans ([8c0dd67](https://github.com/revanced/revanced-helper/commit/8c0dd67d03d5a1747993da08a5bf82a39de43789))
+
+# @revanced/discord-bot [1.0.0-dev.27](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.26...@revanced/discord-bot@1.0.0-dev.27) (2024-09-05)
+
+
+### Bug Fixes
+
+* **bots/discord:** correct permission check logic ([dd8872c](https://github.com/revanced/revanced-helper/commit/dd8872c027c7e7e1a00f38d659b4d6e79274238c))
+* **bots/discord:** give only removed roles for role presets ([522ad28](https://github.com/revanced/revanced-helper/commit/522ad28fd83565e9ca411dbce86c8447574288fd))
+* **bots/discord:** replace duration parser with a library ([94c4fed](https://github.com/revanced/revanced-helper/commit/94c4fedc06e20051e4123508e3134b97eb84782a))
+
+# @revanced/discord-bot [1.0.0-dev.27](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.26...@revanced/discord-bot@1.0.0-dev.27) (2024-08-23)
+
+
+### Bug Fixes
+
+* **bots/discord:** give only removed roles for role presets ([522ad28](https://github.com/revanced/revanced-helper/commit/522ad28fd83565e9ca411dbce86c8447574288fd))
+* **bots/discord:** replace duration parser with a library ([94c4fed](https://github.com/revanced/revanced-helper/commit/94c4fedc06e20051e4123508e3134b97eb84782a))
+
+# @revanced/discord-bot [1.0.0-dev.26](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.25...@revanced/discord-bot@1.0.0-dev.26) (2024-08-15)
+
+
+### Bug Fixes
+
+* **bots/discord:** correct timer active condition for sticky messages ([96065ff](https://github.com/revanced/revanced-helper/commit/96065ff17584ff99a56ca5008327863ca5a7852b))
+
+# @revanced/discord-bot [1.0.0-dev.25](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.24...@revanced/discord-bot@1.0.0-dev.25) (2024-08-15)
+
+
+### Bug Fixes
+
+* **bots/discord:** allow access to `context` in `/eval` and await result ([99f65f0](https://github.com/revanced/revanced-helper/commit/99f65f07f5f8830c6e8ea4ae171e986af4d3f1f6))
+
+# @revanced/discord-bot [1.0.0-dev.24](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.23...@revanced/discord-bot@1.0.0-dev.24) (2024-08-14)
+
+
+### Bug Fixes
+
+* **bots/discord:** do not remove unrelated reactions ([031fd26](https://github.com/revanced/revanced-helper/commit/031fd26b2619ecafeff3964e50accacb87de6108))
+
+# @revanced/discord-bot [1.0.0-dev.23](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.22...@revanced/discord-bot@1.0.0-dev.23) (2024-08-13)
+
+
+### Features
+
+* **bots/discord:** add `train` commands ([ee90ef2](https://github.com/revanced/revanced-helper/commit/ee90ef247b4bf2b3c0698606b947116f2dc1b868))
+* **bots/discord:** update to newer command definition framework ([97f2795](https://github.com/revanced/revanced-helper/commit/97f2795df4ede4d12a08193dba453c1bc765a4c2))
+
+# @revanced/discord-bot [1.0.0-dev.22](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.21...@revanced/discord-bot@1.0.0-dev.22) (2024-08-10)
+
+
+### Bug Fixes
+
+* **bots/discord:** parse larger units of durations, fix wrong timestamp in mod embed ([6c8dce0](https://github.com/revanced/revanced-helper/commit/6c8dce059366a6ef85f5b8b1794c056515b9f5b6))
+* **bots/discord:** provide discord token for `reload` command ([dd21a5a](https://github.com/revanced/revanced-helper/commit/dd21a5abad560f3d00b8c58912786d4b6bd520e9))
+
+
+### Features
+
+* **bots/discord:** add code to actually scan text files correctly ([80aeb19](https://github.com/revanced/revanced-helper/commit/80aeb1902063140a2e78cfaed9424e5101ab03f1))
+
+# @revanced/discord-bot [1.0.0-dev.21](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.20...@revanced/discord-bot@1.0.0-dev.21) (2024-08-04)
+
+
+### Bug Fixes
+
+* **bots/discord:** correct sticky messages logic ([de8bef6](https://github.com/revanced/revanced-helper/commit/de8bef6520d53a1299f0478458320a7eb75c5e1d))
+* **bots/discord:** make `/eval` work ([eaa25f2](https://github.com/revanced/revanced-helper/commit/eaa25f2eb58a9e2d25bb98633ad668485e099714))
+* **bots/discord:** some configuration values not applying after running `/reload` ([a976dd2](https://github.com/revanced/revanced-helper/commit/a976dd2accc4b74914651245acde0979c30c92f5))
+
+# @revanced/discord-bot [1.0.0-dev.20](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.19...@revanced/discord-bot@1.0.0-dev.20) (2024-08-03)
+
+
+### Bug Fixes
+
+* **bots/discord:** await when putting entries into db ([4da6175](https://github.com/revanced/revanced-helper/commit/4da6175cf58b1fa6144bdc71ec806766d32c1025))
+
+# @revanced/discord-bot [1.0.0-dev.19](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.18...@revanced/discord-bot@1.0.0-dev.19) (2024-08-03)
+
+
+### Bug Fixes
+
+* **bots/discord:** correct whitelist logic ([49c29be](https://github.com/revanced/revanced-helper/commit/49c29bebfbe348ae4e2cc1b3a83bfa41eb26ccd1))
+
+# @revanced/discord-bot [1.0.0-dev.18](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.17...@revanced/discord-bot@1.0.0-dev.18) (2024-08-03)
+
+
+### Bug Fixes
+
+* **bots/discord:** set the `label` property correctly for message scans ([6d463df](https://github.com/revanced/revanced-helper/commit/6d463df586dee5dd8fe8d6cff1c5316f7809b32a))
+
+# @revanced/discord-bot [1.0.0-dev.17](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.16...@revanced/discord-bot@1.0.0-dev.17) (2024-08-02)
+
+
+### Bug Fixes
+
+* **bots/discord/commands/eval:** evaluate in current context ([5925d90](https://github.com/revanced/revanced-helper/commit/5925d902095acef5f6396ca03583a9cbb0862498))
+* **bots/discord:** send right response for after regexes ([a7688fa](https://github.com/revanced/revanced-helper/commit/a7688fa9b91919a87f74071b502cd0a87cd1c1fa))
+
+
+### Features
+
+* **bots/discord:** update example config file ([bc9951c](https://github.com/revanced/revanced-helper/commit/bc9951c9b5e007c3e1b3076aa0966ccf29bb18bc))
+
+# @revanced/discord-bot [1.0.0-dev.16](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.15...@revanced/discord-bot@1.0.0-dev.16) (2024-08-02)
+
+
+### Bug Fixes
+
+* **bots/discord:** open database as read-write ([c366840](https://github.com/revanced/revanced-helper/commit/c36684091dddf67880505dc459e4334a8a5492f4))
+* **bots/discord:** remove bad text channel checks ([f5939e2](https://github.com/revanced/revanced-helper/commit/f5939e25288fea2022fdeec9085ecb9ffada6111))
+* **bots/discord:** remove redundant footer for response embeds ([412e003](https://github.com/revanced/revanced-helper/commit/412e00317d1eaca23e9c1375e16f94a5f2fa8d86))
+
+
+### Features
+
+* **bots/discord/commands:** add `reload` command ([6875b32](https://github.com/revanced/revanced-helper/commit/6875b32fd0c6ce3034da9dc6c704d425afb26f2e))
+
+# @revanced/discord-bot [1.0.0-dev.15](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.14...@revanced/discord-bot@1.0.0-dev.15) (2024-07-31)
+
+
+### Bug Fixes
+
+* **bots/discord:** import `config` from context ([763ef25](https://github.com/revanced/revanced-helper/commit/763ef253f9d4ff70a8b79969a7f4f41cba7f3c59))
+
+
+### Features
+
+* **bots/discord:** add sticky messages ([bf66155](https://github.com/revanced/revanced-helper/commit/bf661556e131bf0ef24e47f658fbcd701960e312))
+
+# @revanced/discord-bot [1.0.0-dev.14](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.13...@revanced/discord-bot@1.0.0-dev.14) (2024-07-31)
+
+
+### Bug Fixes
+
+* **bots/discord:** always true check causing no messages to be scanned ([98ec37b](https://github.com/revanced/revanced-helper/commit/98ec37b5d18cade85270ab83b0ed0abe41244dd9))
+* other small issues ([bc437a5](https://github.com/revanced/revanced-helper/commit/bc437a5ec7ce1d339094d608e2a61ac5f460c163))
+
+
+### Features
+
+* **bots/discord:** add more options for curing, fix default regex ([1a4ec1e](https://github.com/revanced/revanced-helper/commit/1a4ec1ece80becd9156582cc490f6681cb2a1f39))
+* **bots/discord:** allow admins to bypass permission checks ([620f933](https://github.com/revanced/revanced-helper/commit/620f9339f0737b79d72c66d90ffa42ea3f987710))
+
+# @revanced/discord-bot [1.0.0-dev.13](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.12...@revanced/discord-bot@1.0.0-dev.13) (2024-07-30)
+
+
+### Bug Fixes
+
+* **bots/discord:** broken regex when prefix set to special characters ([ab62e55](https://github.com/revanced/revanced-helper/commit/ab62e55e76005f5999d7413d1158e54053f28d1f))
+
+# @revanced/discord-bot [1.0.0-dev.12](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.11...@revanced/discord-bot@1.0.0-dev.12) (2024-07-30)
+
+
+### Bug Fixes
+
+* **bots/discord:** deployment runtime errors due to minification ([a60c60c](https://github.com/revanced/revanced-helper/commit/a60c60c0f994a4c256b7d0582e99a1731209cf49))
+
+# @revanced/discord-bot [1.0.0-dev.11](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.10...@revanced/discord-bot@1.0.0-dev.11) (2024-07-30)
+
+
+### Bug Fixes
+
+* **bots/discord:** reset counter when reconnected to api, redo message scan filter logic ([d234d79](https://github.com/revanced/revanced-helper/commit/d234d79310caed9c43e14a905f9ef46a110e071d))
+
+# @revanced/discord-bot [1.0.0-dev.10](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.9...@revanced/discord-bot@1.0.0-dev.10) (2024-07-30)
+
+
+### Bug Fixes
+
+* **bots/discord:** hanging process when disconnecting from API too many times ([d31616e](https://github.com/revanced/revanced-helper/commit/d31616ebcba6f1dcd8bde183bcb8d1adb1501b61))
+
+# @revanced/discord-bot [1.0.0-dev.9](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.8...@revanced/discord-bot@1.0.0-dev.9) (2024-07-30)
+
+
+### Features
+
+* **bots/discord:** framework changes and new features ([646ec8d](https://github.com/revanced/revanced-helper/commit/646ec8da87617e6c8f48a89e8054e2cba91da549))
+
+# @revanced/discord-bot [1.0.0-dev.8](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.7...@revanced/discord-bot@1.0.0-dev.8) (2024-07-28)
+
+
+### Bug Fixes
+
+* **bots/discord:** cross-device link build errors ([38c0699](https://github.com/revanced/revanced-helper/commit/38c06997b4d0f7bb3f1e62618a5e3f088c522e30))
+
+
+### Features
+
+* **bots/discord:** blacklist and whitelist for filters ([cdb6001](https://github.com/revanced/revanced-helper/commit/cdb600195520dba33110c40841629259e317055e))
+
+# @revanced/discord-bot [1.0.0-dev.7](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.6...@revanced/discord-bot@1.0.0-dev.7) (2024-07-25)
+
+
+### Bug Fixes
+
+* **bot/discord:** start remove preset timeout for `role-preset` command ([cbf9116](https://github.com/revanced/revanced-helper/commit/cbf91162e27dd4c1ecb976927ab708f1d882abca))
+* **bots/discord:** only check for member permissions when specified while correcting responses ([b79a1c7](https://github.com/revanced/revanced-helper/commit/b79a1c7575e94c3e62654c87775cac497be4a50a))
+* **bots/discord:** set timeout for eligible mutes to unmute faster ([1f5c5a9](https://github.com/revanced/revanced-helper/commit/1f5c5a92a639973b83a1204355538936e69a4454))
+
+
+### Features
+
+* **bots/discord:** add `replyToReplied` option in response config ([27662ed](https://github.com/revanced/revanced-helper/commit/27662ed91a79bfac7d3f091834e859a7b57366ce))
+
+# @revanced/discord-bot [1.0.0-dev.6](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.5...@revanced/discord-bot@1.0.0-dev.6) (2024-07-23)
+
+
+### Bug Fixes
+
+* **bots/discord:** ci issues causing database to not be auto generated ([673aa18](https://github.com/revanced/revanced-helper/commit/673aa189bef1009a3e32ba3b1291a5ee84f2def3))
+
+# @revanced/discord-bot [1.0.0-dev.5](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.4...@revanced/discord-bot@1.0.0-dev.5) (2024-07-23)
+
+# @revanced/discord-bot [1.0.0-dev.4](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.3...@revanced/discord-bot@1.0.0-dev.4) (2024-07-23)
+
+
+### Bug Fixes
+
+* **bots/discord:** wrong database schema path ([875bd20](https://github.com/revanced/revanced-helper/commit/875bd209b252566414bf89349839cabc01697e1c))
+
+# @revanced/discord-bot [1.0.0-dev.3](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.2...@revanced/discord-bot@1.0.0-dev.3) (2024-07-23)
+
+
+### Bug Fixes
+
+* **bots/discord:** revert dist denesting, fixes config not found ([0d4898d](https://github.com/revanced/revanced-helper/commit/0d4898dae8b26f8466d3f6b8f62875866f581644))
+
+# @revanced/discord-bot [1.0.0-dev.2](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.1...@revanced/discord-bot@1.0.0-dev.2) (2024-07-23)
+
+
+### Features
+
+* **bots/discord:** don't nest builds in src directory, autogen db when missing ([4834685](https://github.com/revanced/revanced-helper/commit/48346851864c4d4b6276388644dd24ce16222b3e))
+
+# @revanced/discord-bot 1.0.0-dev.1 (2024-07-22)
+
+
+### Bug Fixes
+
+* **bots/discord/commands/mute:** use existing `parseDuration` util function' ([3e07429](https://github.com/revanced/revanced-helper/commit/3e07429664f7dbb6ce653083e0adb1a232737fde))
+* **bots/discord/commands/unmute:** fix option description and embeds ([7fdf8c0](https://github.com/revanced/revanced-helper/commit/7fdf8c0dc722e21fe5a3ad6ef8d3a306ef85f532))
+* **bots/discord/commands:** minor issues ([3b2596e](https://github.com/revanced/revanced-helper/commit/3b2596e748cf2cde1500ef2ded55f0faabc2c272))
+* **bots/discord/commands:** refactor and add checks ([a2bf3ea](https://github.com/revanced/revanced-helper/commit/a2bf3eade99b46f9ffb55d45b8caf1bcf3d22a9b))
+* **bots/discord/database:** fix schema for role presets ([4aa138a](https://github.com/revanced/revanced-helper/commit/4aa138a9af8db7093ef637470fcfdea1f5341236))
+* **bots/discord/scripts:** unintentional escaping on windows ([09dc706](https://github.com/revanced/revanced-helper/commit/09dc70632da0597fdb26677acee3f6fccbb2b9b5))
+* **bots/discord/utils/discord/embeds:** set thumbnail on moderation embeds ([b056291](https://github.com/revanced/revanced-helper/commit/b056291ad0f2e2eac5eec8aa71f15dbc769aa0f9))
+* **bots/discord/utils/discord/rolePresets:** correct property access for presets ([4c6ad11](https://github.com/revanced/revanced-helper/commit/4c6ad11be30c1d6af97c4ae40fc62d05fa7bdd57))
+* **bots/discord/utils/discord:** add `moderation` module related functions ([7e8270f](https://github.com/revanced/revanced-helper/commit/7e8270f7d260322e1950e058b221ab088bd595d0))
+* **bots/discord/utils/duration:** fix empty string returning with duration is 0 ([83c314e](https://github.com/revanced/revanced-helper/commit/83c314ef5f721abc355272db0e4c182dcfe5d943))
+* **bots/discord:** apply active role presets if members rejoin ([f50b26b](https://github.com/revanced/revanced-helper/commit/f50b26b82d66c88fd1dbb8c07d77c177c0e781df))
+* **bots/discord:** check token before connecting to bot api ([f3e4408](https://github.com/revanced/revanced-helper/commit/f3e4408aa28fb6a9d21365af8c1bea3d07b481de))
+* **bots/discord:** clear role presets after they expire ([faa81f4](https://github.com/revanced/revanced-helper/commit/faa81f4d887eaeae809651f5b68187d033a260f2))
+* **bots/discord:** connect to discord API even if initial bot API connection fails ([6658b58](https://github.com/revanced/revanced-helper/commit/6658b582dbeba7e072a7a04c4efa255e7f634aef))
+* **bots/discord:** do decancer after resetting nickname ([0303fe3](https://github.com/revanced/revanced-helper/commit/0303fe3e367c07e92f831365d5548ca5b03435b2))
+* **bots/discord:** follow-up if reply is already sent when error ([f75060b](https://github.com/revanced/revanced-helper/commit/f75060bc9cda44902cf872def73c116a6df039d7))
+* **bots/discord:** messed up file name for `unmute` command ([399dca7](https://github.com/revanced/revanced-helper/commit/399dca71538fe5c8831977694a97058254a17578))
+* **bots/discord:** owners cannot bypass checks on some commands ([39cba97](https://github.com/revanced/revanced-helper/commit/39cba973418027ba6ed67e1ae5ab5c6458807562))
+* **bots/discord:** remove auto-generated files ([fb8af00](https://github.com/revanced/revanced-helper/commit/fb8af008661bf37389e01cba19d64a8b4fc82139))
+* **bots/discord:** remove usage of macros ([7f27c56](https://github.com/revanced/revanced-helper/commit/7f27c5607ceeeef56d67097e88f68caa1b8791b3))
+* **bots/discord:** remove useless feature ([d830e48](https://github.com/revanced/revanced-helper/commit/d830e48bc2de7aa457eab3a5f96ae652a93178f9))
+* **bots/discord:** use `APIEmbed` for response config ([35b9448](https://github.com/revanced/revanced-helper/commit/35b944800a3943c187d5b0e0d3e465ad7d2056fe))
+* **bots/discord:** use env for initializing database ([af3759c](https://github.com/revanced/revanced-helper/commit/af3759caf428fada3b3f4a51852543d6fb280018))
+* **bots/discord:** wrong command file path being imported ([fa0159c](https://github.com/revanced/revanced-helper/commit/fa0159c3a8dd4dad8778ccdb75b9e7c02ebbb64f))
+* config file not being read ([474a8be](https://github.com/revanced/revanced-helper/commit/474a8be4af4eb2bae6e80a893439d846ad4f7503))
+* **discord-bot:** also execute slash commands ([f0d45b2](https://github.com/revanced/revanced-helper/commit/f0d45b2c926ed753e2d21f2e06e24d7e6c43880a))
+* **discord-bot:** check for role position ([d332043](https://github.com/revanced/revanced-helper/commit/d332043b1a4bb7ac9698a2fc912832e184130b4b))
+* **discord-bot:** check if the member has the role ([9bff68c](https://github.com/revanced/revanced-helper/commit/9bff68c8c40c692764e4dec15a058e35059efbc9))
+* **discord-bot:** not executing slash commands ([aa08087](https://github.com/revanced/revanced-helper/commit/aa0808768b90844c5fbd3e75d9f2d01c723b0151))
+* **discord-bot:** only send lowercased text ([7803758](https://github.com/revanced/revanced-helper/commit/78037580dc92883f5ca21157e45268850cb5db90))
+* dislike button not working properly ([85eba55](https://github.com/revanced/revanced-helper/commit/85eba554247738066af72a8efd0de215ec1164dc))
+* fix deprecation ([4373ede](https://github.com/revanced/revanced-helper/commit/4373ede855333f209676551162a525238656e1f8))
+* fix the fiter for the interaction collector ([a9ff003](https://github.com/revanced/revanced-helper/commit/a9ff00394a73f68a6793c2b35ff184675ee5a72c))
+* ignore message if there's no content ([3cbebc2](https://github.com/revanced/revanced-helper/commit/3cbebc284277808495e64cf0fb47c555924ad9c5))
+* move modules to `/bots` ([cd7156e](https://github.com/revanced/revanced-helper/commit/cd7156e792e65777ad1ab5a6f5d828b9ef6a9754))
+* trainAI not using the bin location ([bd29943](https://github.com/revanced/revanced-helper/commit/bd2994388bc65f720120ef49edb6ba8163260309))
+
+
+### chore
+
+* fix more build issues ([77fefb9](https://github.com/revanced/revanced-helper/commit/77fefb9bef286a22f40a4d76b79c64fcc5a2467f))
+
+
+### Features
+
+* add wit.ai support ([1909e2c](https://github.com/revanced/revanced-helper/commit/1909e2c42148d635dcd045c738d88f65c8be16e3))
+* **bots/discord/commands/reply:** send stacktrace when failed ([9f1ac37](https://github.com/revanced/revanced-helper/commit/9f1ac379276c11da65235577a9c6717e01cb02eb))
+* **bots/discord/commands:** add `ban` and `unban` commands ([dc4863d](https://github.com/revanced/revanced-helper/commit/dc4863dc208b3fede4d4def323306ab58daffe04))
+* **bots/discord/commands:** add `eval` command ([e64d1da](https://github.com/revanced/revanced-helper/commit/e64d1da00cc2ba718da5a4b0da141fe86a0e48d2))
+* **bots/discord/commands:** add `mute` and `unmute` commands ([c0fa2fe](https://github.com/revanced/revanced-helper/commit/c0fa2fe1c36acdc7c52cde277aa7da867065f55e))
+* **bots/discord/commands:** add `purge` and `role-preset` commands ([fb01ce5](https://github.com/revanced/revanced-helper/commit/fb01ce57400130c93751a11573eb444c0ba103eb))
+* **bots/discord/commands:** allow process exception in `exception-test` ([ca47535](https://github.com/revanced/revanced-helper/commit/ca475356ad95fec86e8e8b5bf4bbf17b70add5fe))
+* **bots/discord/utils/discord/embeds:** expose `applyCommonEmbedStyles` fn ([2d794ed](https://github.com/revanced/revanced-helper/commit/2d794ede7d7a208bd3616c45e8e6d2a2cd83e9ed))
+* **bots/discord/utils/embeds:** make title parameter nullable ([ee885ca](https://github.com/revanced/revanced-helper/commit/ee885ca7585a55fdc31e137ae29dc13a37ce2fb2))
+* **bots/discord/utils/fs:** use `recursive` option for listing files ([da21e1a](https://github.com/revanced/revanced-helper/commit/da21e1a6f76deaeb477203b04263bd170863825b))
+* **bots/discord/utils:** add duration utility ([a9add9e](https://github.com/revanced/revanced-helper/commit/a9add9ea9affb42bdfcb17cf4b268feec5729854))
+* **bots/discord/utils:** add functions for role presets ([fb32a04](https://github.com/revanced/revanced-helper/commit/fb32a04ad38be8d0836dc99259b6ef05a0825830))
+* **bots/discord/utils:** allow loading commands from custom dir ([8b690b8](https://github.com/revanced/revanced-helper/commit/8b690b879bb5c6023c8fc863afbd9fd1d02719bb))
+* **bots/discord:** add `api.disconnectRetryInterval` config ([2f86586](https://github.com/revanced/revanced-helper/commit/2f8658617923c07f6847cbf1fdfc5f5379d95b6c))
+* **bots/discord:** add `moderation.roles` config to be used in `moderation` commands ([39d5b3a](https://github.com/revanced/revanced-helper/commit/39d5b3a479b4d856aabe12cc31177c24f88ae23e))
+* **bots/discord:** add `ocrTriggers` resp config, embed footer scan mode ([744a56a](https://github.com/revanced/revanced-helper/commit/744a56a4fdc8844e37959a88bcf81ee39fe726ef))
+* **bots/discord:** add a better way to manage databases ([a68d726](https://github.com/revanced/revanced-helper/commit/a68d72687584332587455962b0202a306288057d))
+* **bots/discord:** add more fallbacks for decancering ([2e1e009](https://github.com/revanced/revanced-helper/commit/2e1e009b4272495798313bd3bd61f258875c62e1))
+* **bots/discord:** add source ([f9d50a0](https://github.com/revanced/revanced-helper/commit/f9d50a0a6bef8beaa428a0a555bfa4f879f685f1))
+* **bots/discord:** improve logs ([6abb740](https://github.com/revanced/revanced-helper/commit/6abb7409945c10bd3af451fb45ef4b4d4ebe9489))
+* **bots/discord:** sanitize `BasicDatabase` inputs ([fd76e0a](https://github.com/revanced/revanced-helper/commit/fd76e0af72fe28b414ae3b5e8d3886e58561e57e))
+* **bots/discord:** support nickname decancering ([1723e8c](https://github.com/revanced/revanced-helper/commit/1723e8cacf96e8c6bdee22cfd30e89524fdcef74))
+* **bots/discord:** switch to `drizzle-orm` ([e204b7b](https://github.com/revanced/revanced-helper/commit/e204b7b7566fd7fa423baef32977a8575d44a9e0))
+* **bots/discord:** update config ([197d2ac](https://github.com/revanced/revanced-helper/commit/197d2acea89c38e43858d52736508d449152e804))
+* discord bot scanning messages ([d1bd3b2](https://github.com/revanced/revanced-helper/commit/d1bd3b2b7e4985a64e9b070ab006cc6f3508c46e))
+* **discord-bot:** a way to train AI ([355a508](https://github.com/revanced/revanced-helper/commit/355a50803adc85b5579155b55ddbba4fa0449237))
+* **discord-bot:** command handler and train cmd ([6aee8a4](https://github.com/revanced/revanced-helper/commit/6aee8a4c63eb108800fcb0a23ca61f200d8f1f2a))
+* **discord-bot:** event handler ([0ad5ece](https://github.com/revanced/revanced-helper/commit/0ad5ece08593c0db111fa4a592b42c6e0348fd1c))
+* GODEL AI ([0ba525c](https://github.com/revanced/revanced-helper/commit/0ba525c4a5802106d582c75f713728accf2f151a))
+* initalize discord bot ([bb4a5a7](https://github.com/revanced/revanced-helper/commit/bb4a5a77eefbc7ac88536f73a111df1050b235e7))
+* initialize helper client ([7f9ca77](https://github.com/revanced/revanced-helper/commit/7f9ca77e0331ec143160ee51ed7c3aa9e4e70b9c))
+* message buttons for training ([6551ca9](https://github.com/revanced/revanced-helper/commit/6551ca9dadc2e3ddfe98875e80ed61f7d71a1651))
+* platform specific responses ([18e57b0](https://github.com/revanced/revanced-helper/commit/18e57b0c320732a937bb60db11c5d6794ed11522))
+* prettier and eslint ([1c27ccb](https://github.com/revanced/revanced-helper/commit/1c27ccb17c85f0f6982db45de426181d2c231d0e))
+* refactor and new features ([#7](https://github.com/revanced/revanced-helper/issues/7)) ([8b9f45d](https://github.com/revanced/revanced-helper/commit/8b9f45dc22de29dc2ccb1cfab9a026db00457e25))
+* run bots in one process ([d26d533](https://github.com/revanced/revanced-helper/commit/d26d53317440c64fb775cea609a87d29be6c8b40))
+* training and replies changed ([715aa91](https://github.com/revanced/revanced-helper/commit/715aa918cf84213c9b19591a398d7532eb3f232a))
+* **utils/discord/embeds:** allow adding extra fields for moderation embeds ([49ce9a7](https://github.com/revanced/revanced-helper/commit/49ce9a7ca3d8558b73a9b94dfe7a01d809db6fff))
+
+
+### BREAKING CHANGES
+
+* In `@revanced/discord-bot`, its environment variable
+ `DATABASE_URL` has been renamed to `DATABASE_PATH`
+ and the `file:` prefix is no longer needed
diff --git a/bots/discord/Dockerfile b/bots/discord/Dockerfile
new file mode 100644
index 0000000..7c02d84
--- /dev/null
+++ b/bots/discord/Dockerfile
@@ -0,0 +1,18 @@
+# This file should be triggered from the monorepo root
+FROM oven/bun:latest AS base
+
+FROM base AS build
+
+WORKDIR /build
+COPY . .
+RUN bun install --frozen-lockfile
+RUN cd bots/discord && bun run build
+
+FROM base AS release
+
+WORKDIR /app
+COPY --from=build /build/bots/discord/dist /app
+
+USER 1000:1000
+
+ENTRYPOINT [ "bun", "--bun", "run", "src/index.js" ]
diff --git a/bots/discord/README.md b/bots/discord/README.md
new file mode 100755
index 0000000..fdf73ec
--- /dev/null
+++ b/bots/discord/README.md
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Continuing the legacy of Vanced
+
+
+# 🤖 ReVanced Discord Bot
+
+
+
+Discord bot assisting ReVanced's Discord server.
+
+## 📚 Documentation
+
+Documentation are provided [here](./docs/README.md).
+
+## 📄 License
+
+**ReVanced Discord Bot** adopts the [GNU General Public License 3.0](./LICENSE), tl;dr: You may copy, distribute and modify the software as long as you track changes/dates in source files. Any modifications to or software including (via compiler) GPL-licensed code must also be made available under the GPL along with build & install instructions.
diff --git a/bots/discord/config.js b/bots/discord/config.js
new file mode 100644
index 0000000..1b04f24
--- /dev/null
+++ b/bots/discord/config.js
@@ -0,0 +1,122 @@
+// @ts-check
+
+/**
+ * @type {import('./config.schema').Config}
+ */
+export default {
+ prefix: '!',
+ admin: {
+ users: ['USER_ID_HERE'],
+ roles: {
+ GUILD_ID_HERE: ['ROLE_ID_HERE'],
+ },
+ },
+ stickyMessages: {
+ GUILD_ID_HERE: {
+ CHANNEL_ID_HERE: {
+ message: {
+ content: 'This is a sticky message!',
+ },
+ timeout: 60000,
+ forceSendTimeout: 300000,
+ },
+ },
+ },
+ moderation: {
+ cure: {
+ minimumNameLength: 3,
+ removeCharactersRegex: /[^a-zA-Z0-9 \-_]/g,
+ defaultName: 'Server member',
+ },
+ roles: ['ROLE_ID_HERE'],
+ log: {
+ channel: 'CHANNEL_ID_HERE',
+ // Optional
+ thread: 'THREAD_ID_HERE',
+ },
+ },
+ rolePresets: {
+ guilds: {
+ GUILD_ID_HERE: {
+ preset: {
+ give: ['ROLE_ID_HERE'],
+ take: ['ROLE_ID_HERE'],
+ },
+ anotherPreset: {
+ give: ['ROLE_ID_HERE'],
+ take: ['ROLE_ID_HERE'],
+ },
+ },
+ },
+ checkExpiredEvery: 3600,
+ },
+ messageScan: {
+ scanBots: false,
+ scanOutsideGuilds: false,
+ filter: {
+ whitelist: {
+ channels: ['CHANNEL_ID_HERE'],
+ roles: ['ROLE_ID_HERE'],
+ users: ['USER_ID_HERE'],
+ },
+ blacklist: {
+ channels: ['CHANNEL_ID_HERE'],
+ roles: ['ROLE_ID_HERE'],
+ users: ['USER_ID_HERE'],
+ },
+ },
+ humanCorrections: {
+ falsePositiveLabel: 'false_positive',
+ allow: {
+ members: {
+ permissions: 8n,
+ roles: ['ROLE_ID_HERE'],
+ },
+ },
+ },
+ attachments: {
+ scanAttachments: true,
+ allowedMimeTypes: ['image/jpeg', 'image/png', 'image/webp', 'text/plain'],
+ maxTextFileSize: 512000,
+ },
+ responses: [
+ {
+ filterOverride: {
+ whitelist: {
+ channels: ['CHANNEL_ID_HERE'],
+ roles: ['ROLE_ID_HERE'],
+ users: ['USER_ID_HERE'],
+ },
+ blacklist: {
+ channels: ['CHANNEL_ID_HERE'],
+ roles: ['ROLE_ID_HERE'],
+ users: ['USER_ID_HERE'],
+ },
+ },
+ triggers: {
+ text: [/^regexp?$/, { label: 'label', threshold: 0.85 }],
+ },
+ response: {
+ embeds: [
+ {
+ title: 'Embed title',
+ description: 'Embed description',
+ fields: [
+ {
+ name: 'Field name',
+ value: 'Field value',
+ },
+ ],
+ },
+ ],
+ },
+ },
+ ],
+ },
+ logLevel: 'log',
+ api: {
+ url: 'ws://127.0.0.1:3000',
+ disconnectLimit: 3,
+ disconnectRetryInterval: 10000,
+ },
+}
diff --git a/bots/discord/config.schema.ts b/bots/discord/config.schema.ts
new file mode 100644
index 0000000..cb118d4
--- /dev/null
+++ b/bots/discord/config.schema.ts
@@ -0,0 +1,96 @@
+import type { BaseMessageOptions } from 'discord.js'
+
+export type Config = {
+ prefix?: string
+ admin?: {
+ users?: string[]
+ roles?: Record
+ }
+ stickyMessages?: Record>
+ moderation?: {
+ roles: string[]
+ cure?: {
+ minimumNameLength?: number
+ removeCharactersRegex?: RegExp
+ defaultName: string
+ }
+ log?: {
+ channel: string
+ thread?: string
+ }
+ }
+ rolePresets?: {
+ checkExpiredEvery: number
+ guilds: Record>
+ }
+ messageScan?: {
+ scanBots?: boolean
+ scanOutsideGuilds?: boolean
+ attachments?: {
+ scanAttachments?: boolean
+ allowedMimeTypes?: string[]
+ maxTextFileSize?: number
+ }
+ filter?: {
+ whitelist?: Filter
+ blacklist?: Filter
+ }
+ humanCorrections: {
+ falsePositiveLabel: string
+ allow?: {
+ users?: string[]
+ members?: {
+ permissions?: bigint
+ roles?: string[]
+ }
+ }
+ }
+ responses: ConfigMessageScanResponse[]
+ }
+ logLevel: 'none' | 'error' | 'warn' | 'info' | 'log' | 'trace' | 'debug'
+ api: {
+ url: string
+ disconnectLimit?: number
+ disconnectRetryInterval?: number
+ }
+}
+
+export type StickyMessageConfig = {
+ timeout: number
+ forceSendTimeout?: number
+ message: BaseMessageOptions
+}
+
+export type RolePresetConfig = {
+ give: string[]
+ take: string[]
+}
+
+export type ConfigMessageScanResponse = {
+ triggers: {
+ text?: Array
+ image?: Array
+ }
+ filterOverride?: NonNullable['filter']
+ response: ConfigMessageScanResponseMessage | null
+ respondToReply?: boolean
+}
+
+export type ConfigMessageScanResponseLabelConfig = {
+ /**
+ * Label name
+ */
+ label: string
+ /**
+ * Confidence threshold
+ */
+ threshold: number
+}
+
+export type Filter = {
+ roles?: string[]
+ users?: string[]
+ channels?: string[]
+}
+
+export type ConfigMessageScanResponseMessage = BaseMessageOptions
diff --git a/bots/discord/docker-compose.example.yml b/bots/discord/docker-compose.example.yml
new file mode 100644
index 0000000..c40f9d8
--- /dev/null
+++ b/bots/discord/docker-compose.example.yml
@@ -0,0 +1,9 @@
+services:
+ websocket-api:
+ container_name: revanced-bot-discord
+ image: ghcr.io/revanced/revanced-bot-discord:latest
+ volumes:
+ - /data/revanced-bot-discord:/app
+ ports:
+ - 3000:3000
+ restart: unless-stopped
\ No newline at end of file
diff --git a/bots/discord/docs/1_configuration.md b/bots/discord/docs/1_configuration.md
new file mode 100644
index 0000000..0a6a634
--- /dev/null
+++ b/bots/discord/docs/1_configuration.md
@@ -0,0 +1,73 @@
+# ⚙️ Configuration
+
+This page tells you how to configure the bot.
+
+## 📄 JSON config
+
+See [`config.ts`](../config.ts).
+
+---
+
+#### `config.owners`
+
+User IDs of the owners of the bot. Only add owners when needed.
+
+#### `config.guilds`
+
+Servers the bot is allowed to be and register commands in.
+
+#### `config.logLevel`
+
+The level of logs to print to console. If the level is more important or equally important to set level, it will be forwarded to the console.
+
+The possible levels (sorted by their importance descendingly) are:
+
+- `none`
+- `fatal`
+- `error`
+- `warn`
+- `info`
+- `log`
+- `debug`
+
+#### `config.api.url`
+
+WebSocket URL to connect to (including port). Soon auto-discovery will be implemented.
+
+#### `config.api.disconnectLimit`
+
+Amount of times to allow disconnecting before exiting with code `1`.
+
+#### `config.messageScan`
+
+[Please see the next page.](./2_adding_autoresponses.md)
+
+#### `config.moderation`
+
+TBD.
+
+#### `config.rolePresets`
+
+TBD.
+
+## 🟰 Environment variables
+
+See [`.env.example`](../.env.example).
+You can set environment variables in your shell or use a `.env` file which **Bun will automatically load**.
+
+---
+
+#### `DISCORD_TOKEN`
+
+The Discord bot token.
+
+#### `DATABASE_PATH`
+
+The database path.
+Example values are: `./revanced.db`, `db.sqlite3`, `../some/path/discord_bot.sqlite`
+
+## ⏭️ What's next
+
+The next page will tell you how to configure auto-responses.
+
+Continue: [🗣️ Adding auto-responses](./2_adding_autoresponses.md)
diff --git a/bots/discord/docs/2_adding_autoresponses.md b/bots/discord/docs/2_adding_autoresponses.md
new file mode 100644
index 0000000..5d6a504
--- /dev/null
+++ b/bots/discord/docs/2_adding_autoresponses.md
@@ -0,0 +1,89 @@
+# 🗣️ Adding auto-responses
+
+This is referring to `config.messageScan`.
+
+## 🧱 Filters
+
+You can add filters to blacklist or whitelist a user from message scanning preventing auto-responses.
+
+### `filter.roles` & `filter.users` & `filter.channels`
+
+Roles, users, and channels which will be affected by the blacklist/whitelist rule.
+
+### `filter.whitelist`
+
+Whether to use whitelist (`true`) or blacklist (`false`) mode.
+
+- Blacklist mode **will refuse** to scan messages that match any of the filters above
+- Whitelist mode **will only** scan messages that match any of the filters above.
+
+## 💬 Responses
+
+The `responses` field is array containing response configurations.
+
+### Adding a message response
+
+The `responses[n].response` field contains the embed data that the bot should send. If it is set to `null`, the bot will not send a response or delete the current response if editing (useful for catching false positives).
+
+```ts
+response: {
+ title: 'Embed title',
+ description: 'Embed description',
+ fields: [
+ {
+ name: 'Field name',
+ value: 'Field value',
+ },
+ ],
+}
+
+// or if it's a false positive label (for example)
+response: null
+```
+
+### Adding triggers
+
+A response can be triggered by multiple ways[^1], which can be specified in the `response[n].triggers` object.
+
+You can add a trigger for text messages which can either be a regular expression, or a label match config (NLP) into the `responses.triggers.text` array.
+However, if you want **only OCR results** to match a certain regular expression, you can put them into the `response.triggers.image` array instead.
+
+```ts
+triggers: {
+ // Text messages
+ text: [
+ /cool regex/i,
+ {
+ label: 'some_label',
+ threshold: 0.8,
+ },
+ ],
+ // Text messages with image attachments (OCR results)
+ image: [
+ /image regex/i
+ ]
+},
+```
+
+### Override a filter
+
+You can also override the filter of the current response by supplying the [filter object](#configmessagescanfilter) into the `response.filterOverride` field.
+
+```ts
+filterOverride: {
+ // will only respond to members with this role
+ roles: ['ROLE_ID'],
+ // or in this channel
+ channels: ['CHANNEL_ID'],
+ whitelist: true,
+},
+```
+
+[^1]: Possible triggers are regular expressions or [label configurations](../config.schema.ts#L83).
+ Label configurations are only allowed for **text scans** currently. However in the future, it may also come for image scans. There is nothing preventing this from happening.
+
+## ⏭️ What's next
+
+The next page will tell you how to run and bundle the bot.
+
+Continue: [🏃🏻♂️ Running the bot](./3_running_and_deploying.md)
diff --git a/bots/discord/docs/3_running_and_deploying.md b/bots/discord/docs/3_running_and_deploying.md
new file mode 100644
index 0000000..05a18e6
--- /dev/null
+++ b/bots/discord/docs/3_running_and_deploying.md
@@ -0,0 +1,64 @@
+# 🏃🏻♂️ Running and deploying
+
+There are two methods to run the bot. Choose one that suits best for the situation.
+
+## 👷🏻 Development mode (recommended)
+
+There will be no compilation step, and Bun will automatically watch changes and restart the bot for you.
+
+You can quickly start the bot by running:
+
+```sh
+bun dev
+```
+
+## 📦 Building
+
+To build the bot, you can run:
+
+```sh
+bun run build
+```
+
+The distribution files will be placed inside the `dist` directory. Inside will include:
+
+- The default configuration for the bot
+- Compiled source files of the bot
+
+## ✈️ Deploying
+
+To deploy the bot, you'll need to:
+
+1. [Build the bot as seen in the previous step](#-building)
+2. Run the `reload-slash-commands` script
+ This is to ensure all commands are registered, so they can be used.
+ **It may take up to 2 hours until **global** commands are updated. This is a Discord limitation.**
+
+ ```sh
+ # Assuming you're in the workspace's root (NOT REPOSITORY ROOT)
+ bun run scripts/reload-slash-commands.ts
+ ```
+
+3. Copy contents of the `dist` directory
+
+ ```sh
+ # For instance, we'll copy them both to /usr/src/discord-bot
+ # Assuming you're in the workspace's root (NOT REPOSITORY ROOT)
+ cp -R ./dist/* /usr/src/discord-bot
+ ```
+
+4. Configure environment variables
+ As seen in [`.env.example`](../.env.example). You can also optionally use a `.env` file which **Bun will automatically load**.
+
+5. Finally, run the bot
+
+ ```sh
+ cd /usr/src/discord-bot
+ bun run src/index.js
+ ```
+
+## ⏭️ What's next
+
+The next page will tell you how to add commands and listen to events to the bot.
+
+Continue: [✨ Adding commands and listening to events](./4_commands_and_events.md)
diff --git a/bots/discord/docs/4_commands_and_events.md b/bots/discord/docs/4_commands_and_events.md
new file mode 100644
index 0000000..c1d58b2
--- /dev/null
+++ b/bots/discord/docs/4_commands_and_events.md
@@ -0,0 +1,123 @@
+# ✨ Adding commands and listening to events
+
+Adding commands and listening to new events is easy once you learn the project's structure.
+
+## 🗄️ Project structure
+
+In the source directory, you'll find multiple other directories:
+
+- [Commands](#💬-commands) are located in `src/commands`
+- [Events](#🚩-events) are located in `src/events`
+- [Utility functions](../src/utils) are located in `src/utils`
+
+You'll also find multiple files:
+
+- [`index.ts`](../src/index.ts) is the entry of the bot
+- [`context.ts`](../src/context.ts) is the context object that will be referenced in multiple places
+
+## 💬 Commands
+
+> [!IMPORTANT]
+> You are currently developing with the temporary system which isn't very great in terms of development experience.
+> A new system will be made and pushed soon and all commands will be migrated to it.
+
+If you feel the need to categorize commands into directories, you absolutely can, as the system does not restrict subdirectories.
+
+You can start developing commands with this template:
+
+```ts
+// src/commands/my-command.ts
+
+import { SlashCommandBuilder } from "discord.js";
+import type { Command } from ".";
+
+export default {
+ data: new SlashCommandBuilder()
+ .setName("my-command")
+ .setDescription("My cool command")
+ // DO NOT forget this line!
+ .toJSON(),
+
+ // Member requirements, will only apply to
+ memberRequirements: {
+ // Match mode, can be `all` or `any` (`all` by default)
+ // - All mode means all of the following conditions have to match
+ // - Any mode means one of the following conditions have to match
+ mode: "all",
+ // This will always match in Any mode, which means the member must have one of these roles to pass
+ roles: ["955220417969262612", "973886585294704640"],
+ // Permissions required to execute this command
+ // -1n means bot owners only (default for security reasons)
+ permissions: -1n,
+ },
+
+ // Whether this command should be able to be executed by only bot owners
+ // (true by default)
+ ownerOnly: false,
+
+ // Whether to register this command globally
+ // This is turned off by default for security reasons
+ global: true,
+
+ // What to do when this command executes
+ async execute(_context, interaction) {
+ await interaction.reply({
+ content: "Hello!",
+ });
+ },
+} satisfies Command;
+```
+
+## 🚩 Events
+
+Events are a bit different. We have 2 different event systems for both Discord API and our own bot API. This means the [`src/events`](../src/events) directory will have 2 separate directories inside. They are specific to the respective API, but the utility functions make the experience with both of them very similar.
+
+To start adding events, you can use these templates:
+
+##### Discord event template
+
+```ts
+import { on, once, withContext } from '$utils/discord/events'
+
+on('eventName', async (arg1, arg2, ...) => {
+ // Do something when the event is triggered
+})
+
+once('eventName', async (arg1, arg2, ...) => {
+ // Do something for only a single time after it's triggered, never again
+})
+
+withContext(on, 'eventName', async (context, arg1, arg2, ...) => {
+ // Do some other thing that requires the context object
+})
+```
+
+##### API events template
+
+```ts
+import { on, once } from '$utils/api/events'
+
+on('eventName', async (arg1, arg2, ...) => {
+ // Do something when the event is triggered
+})
+
+once('eventName', async (arg1, arg2, ...) => {
+ // Do something for only a single time after it's triggered, never again
+})
+```
+
+API events are stored in [`src/events/api`](../src/events/api), and Discord events are in [`src/events/discord`](../src/events/discord).
+
+### 📛 Event file naming conventions
+
+Since a single event file can have multiple listeners, you should name exactly what the file handles.
+For example, when a nickname change happens, a member joins, or a member sends a message, the bot is required to cure their nickname. Therefore we would name the event file `curedRequired.ts`.
+
+> [!NOTE]
+> If you need multiple event listeners for the same exact event **but also need more abstraction**, you can put them in a directory with the event name and rename the listeners to what they handle specifically. You can see how we do it in [`src/events/discord/interactionCreate`](../src/events/discord/interactionCreate).
+
+## ⏭️ What's next
+
+The next page will tell you how to create and interact with a database.
+
+Continue: [🫙 Storing data](./5_databases.md)
diff --git a/bots/discord/docs/README.md b/bots/discord/docs/README.md
new file mode 100644
index 0000000..2405c34
--- /dev/null
+++ b/bots/discord/docs/README.md
@@ -0,0 +1,18 @@
+# 🤖 ReVanced Discord Bot
+
+This documentation explains how to start developing, and how to configure the bot.
+
+## 📖 Table of contents
+
+0. [🏗️ Set up the development environment (if you haven't already)](../../../docs/0_development_environment.md)
+1. [⚙️ Configuration](./1_configuration.md)
+2. [🗣️ Adding auto-responses](./2_adding_autoresponses.md)
+3. [🏃🏻♂️ Running the bot](./3_running.md)
+4. [✨ Command and events](./4_commands_and_events.md)
+5. [🫙 Storing data](./5_databases.md)
+
+## ⏭️ Start here
+
+The next page will tell you how to configure the bot.
+
+Continue: [⚙️ Configuration](./1_configuration.md)
diff --git a/bots/discord/drizzle.config.ts b/bots/discord/drizzle.config.ts
new file mode 100644
index 0000000..bebe08d
--- /dev/null
+++ b/bots/discord/drizzle.config.ts
@@ -0,0 +1,10 @@
+import { defineConfig } from 'drizzle-kit'
+
+export default defineConfig({
+ dialect: 'sqlite',
+ schema: './src/database/schemas.ts',
+ out: './.drizzle',
+ dbCredentials: {
+ url: process.env['DATABASE_PATH'] ? `file:./${process.env['DATABASE_PATH']}` : 'file:./db.sqlite3',
+ },
+})
diff --git a/bots/discord/package.json b/bots/discord/package.json
new file mode 100644
index 0000000..b0477e8
--- /dev/null
+++ b/bots/discord/package.json
@@ -0,0 +1,46 @@
+{
+ "name": "@revanced/discord-bot",
+ "type": "module",
+ "private": true,
+ "version": "1.0.0-dev.38",
+ "description": "🤖 Discord bot assisting ReVanced",
+ "main": "src/index.ts",
+ "scripts": {
+ "start": "bun prepare && bun run src/index.ts",
+ "dev": "bun prepare && bun --watch src/index.ts",
+ "build": "bun prepare && bun run scripts/build.ts",
+ "watch": "bun dev",
+ "prepare": "bun run scripts/generate-indexes.ts && bunx --bun drizzle-kit generate --name=schema"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/revanced/revanced-bots.git",
+ "directory": "bots/discord"
+ },
+ "author": "Palm (https://palmdevs.me)",
+ "contributors": [
+ "Palm (https://palmdevs.me)",
+ "ReVanced (https://revanced.app)"
+ ],
+ "license": "GPL-3.0-or-later",
+ "bugs": {
+ "url": "https://github.com/revanced/revanced-bots/issues"
+ },
+ "homepage": "https://github.com/revanced/revanced-bots#readme",
+ "dependencies": {
+ "@discordjs/builders": "^1.10.1",
+ "@discordjs/rest": "^2.4.3",
+ "@revanced/bot-api": "workspace:*",
+ "@revanced/bot-shared": "workspace:*",
+ "chalk": "^5.4.1",
+ "decancer": "^3.2.8",
+ "discord.js": "^14.18.0",
+ "drizzle-orm": "^0.31.4",
+ "parse-duration": "^1.1.2"
+ },
+ "devDependencies": {
+ "@libsql/client": "^0.7.0",
+ "discord-api-types": "^0.37.119",
+ "drizzle-kit": "^0.22.8"
+ }
+}
\ No newline at end of file
diff --git a/bots/discord/scripts/build.ts b/bots/discord/scripts/build.ts
new file mode 100644
index 0000000..f382cfe
--- /dev/null
+++ b/bots/discord/scripts/build.ts
@@ -0,0 +1,23 @@
+import { createLogger } from '@revanced/bot-shared'
+import { cp, exists, rm } from 'fs/promises'
+
+const logger = createLogger()
+
+logger.warn('Cleaning previous build...')
+if (await exists('./dist')) await rm('./dist', { recursive: true })
+
+logger.info('Building bot...')
+await Bun.build({
+ entrypoints: ['./src/index.ts'],
+ outdir: './dist/src',
+ target: 'bun',
+ external: ['./config.js'],
+ sourcemap: 'external',
+})
+
+logger.info('Copying config...')
+await cp('./config.js', './dist/config.js')
+
+logger.info('Copying database schema...')
+await cp('./.drizzle', './dist/.drizzle', { recursive: true })
+await rm('./.drizzle', { recursive: true })
diff --git a/bots/discord/scripts/generate-indexes.ts b/bots/discord/scripts/generate-indexes.ts
new file mode 100644
index 0000000..bf2762d
--- /dev/null
+++ b/bots/discord/scripts/generate-indexes.ts
@@ -0,0 +1,6 @@
+import { join } from 'path'
+import { generateCommandsIndex, generateEventsIndex } from '../src/utils/fs'
+
+await generateCommandsIndex(join(import.meta.dir, '../src/commands'))
+await generateEventsIndex(join(import.meta.dir, '../src/events/discord'))
+await generateEventsIndex(join(import.meta.dir, '../src/events/api'))
diff --git a/bots/discord/scripts/trigger-portainer-webhook.ts b/bots/discord/scripts/trigger-portainer-webhook.ts
new file mode 100644
index 0000000..c2f3855
--- /dev/null
+++ b/bots/discord/scripts/trigger-portainer-webhook.ts
@@ -0,0 +1,4 @@
+import { $ } from 'bun'
+
+const URLEnvironmentVariableName = 'DISCORD_BOT_PORTAINER_WEBHOOK_URL'
+await $`INPUT_WEBHOOK_URL=${process.env[URLEnvironmentVariableName]} bun run ../../node_modules/portainer-service-webhook/dist`
diff --git a/bots/discord/src/classes/Command.ts b/bots/discord/src/classes/Command.ts
new file mode 100644
index 0000000..95cc0be
--- /dev/null
+++ b/bots/discord/src/classes/Command.ts
@@ -0,0 +1,727 @@
+import { ApplicationCommandOptionType, ApplicationCommandType } from 'discord.js'
+import { isAdmin } from '../utils/discord/permissions'
+
+import CommandError, { CommandErrorType } from './CommandError'
+
+import type {
+ APIApplicationCommandChannelOption,
+ CacheType,
+ Channel,
+ ChatInputCommandInteraction,
+ CommandInteraction,
+ CommandInteractionOption,
+ GuildMember,
+ Message,
+ MessageContextMenuCommandInteraction,
+ RESTPostAPIApplicationCommandsJSONBody,
+ RESTPostAPIChatInputApplicationCommandsJSONBody,
+ Role,
+ User,
+ UserContextMenuCommandInteraction,
+ UserResolvable,
+} from 'discord.js'
+import { config } from '../context'
+
+export enum CommandType {
+ ChatGlobal = 1,
+ ChatGuild,
+ ContextMenuUser,
+ ContextMenuMessage,
+ ContextMenuGuildMessage,
+ ContextMenuGuildMember,
+}
+
+export default class Command<
+ const Type extends CommandType = CommandType.ChatGuild,
+ const Options extends If, undefined, CommandOptionsOptions | undefined> = undefined,
+ const AllowMessageCommand extends If, false, boolean> = false,
+> {
+ name: string
+ description: string
+ requirements?: CommandRequirements
+ options?: Options
+ type: Type
+ allowMessageCommand: AllowMessageCommand
+ #execute: CommandExecuteFunction
+
+ static OptionType = ApplicationCommandOptionType
+ static Type = CommandType
+
+ constructor({
+ name,
+ description,
+ requirements,
+ options,
+ type,
+ allowMessageCommand,
+ execute,
+ }: CommandOptions) {
+ this.name = name
+ this.description = description!
+ this.requirements = requirements
+ this.options = options
+ // @ts-expect-error: Default is `CommandType.GuildOnly`, it makes sense
+ this.type = type ?? CommandType.ChatGuild
+ // @ts-expect-error: Default is `false`, it makes sense
+ this.allowMessageCommand = allowMessageCommand ?? false
+ this.#execute = execute
+ }
+
+ isGuildSpecific(): this is Command<
+ CommandType.ChatGuild | CommandType.ContextMenuGuildMember | CommandType.ContextMenuGuildMessage,
+ Options,
+ AllowMessageCommand
+ > {
+ return [
+ CommandType.ChatGuild,
+ CommandType.ContextMenuGuildMessage,
+ CommandType.ContextMenuGuildMember,
+ ].includes(this.type)
+ }
+
+ isContextMenuSpecific(): this is Command<
+ | CommandType.ContextMenuGuildMessage
+ | CommandType.ContextMenuGuildMember
+ | CommandType.ContextMenuUser
+ | CommandType.ContextMenuMessage,
+ undefined,
+ false
+ > {
+ return [
+ CommandType.ContextMenuMessage,
+ CommandType.ContextMenuUser,
+ CommandType.ContextMenuGuildMessage,
+ CommandType.ContextMenuGuildMember,
+ ].includes(this.type)
+ }
+
+ isGuildContextMenuSpecific(): this is Command<
+ CommandType.ContextMenuGuildMessage | CommandType.ContextMenuGuildMember,
+ undefined,
+ false
+ > {
+ return [CommandType.ContextMenuGuildMessage, CommandType.ContextMenuGuildMember].includes(this.type)
+ }
+
+ async onContextMenuInteraction(
+ context: typeof import('../context'),
+ interaction: If<
+ Extends,
+ MessageContextMenuCommandInteraction>,
+ UserContextMenuCommandInteraction>
+ >,
+ ): Promise {
+ if (!this.isGuildSpecific() && !interaction.inGuild())
+ throw new CommandError(CommandErrorType.InteractionNotInGuild)
+
+ const executor = await this.#fetchInteractionExecutor(interaction)
+ const target =
+ this.type === CommandType.ContextMenuGuildMember
+ ? this.isGuildSpecific()
+ ? fetchMember(interaction as CommandInteraction<'raw' | 'cached'>, interaction.targetId)
+ : interaction.client.users.fetch(interaction.targetId)
+ : interaction.channel?.messages.fetch(interaction.targetId)
+
+ if (!target) throw new CommandError(CommandErrorType.FetchManagerNotFound)
+
+ // @ts-expect-error: Type mismatch (again!) because TypeScript is not smart enough
+ return await this.#execute({ ...context, executor, target }, interaction, undefined)
+ }
+
+ async onMessage(
+ context: typeof import('../context'),
+ msg: Message>,
+ args: CommandArguments,
+ ): Promise {
+ if (!this.allowMessageCommand) return
+ if (!this.isGuildSpecific() && !msg.guildId) throw new CommandError(CommandErrorType.InteractionNotInGuild)
+
+ const executor = this.isGuildSpecific()
+ ? await msg.guild?.members.fetch(msg.author)!
+ : await msg.client.users.fetch(msg.author)
+ if (!(await this.canExecute(executor))) throw new CommandError(CommandErrorType.RequirementsNotMet)
+
+ const options = this.options
+ ? ((await this.#resolveMessageOptions(msg, this.options, args)) as CommandExecuteFunctionOptionsParameter<
+ NonNullable
+ >)
+ : undefined
+
+ // @ts-expect-error: Type mismatch (again!) because TypeScript is not smart enough
+ return await this.#execute({ ...context, executor }, msg, options)
+ }
+
+ async #resolveMessageOptions(msg: Message, options: CommandOptionsOptions, args: CommandArguments) {
+ const iterableOptions = Object.entries(options)
+ const _options = {} as unknown
+
+ for (let i = 0; i < iterableOptions.length; i++) {
+ const [name, option] = iterableOptions[i]!
+ const { type, required, description } = option
+ const isSubcommandLikeOption =
+ type === ApplicationCommandOptionType.Subcommand ||
+ type === ApplicationCommandOptionType.SubcommandGroup
+
+ const arg = args[i]
+
+ const expectedType = `${ApplicationCommandOptionType[type]}${required ? '' : '?'}`
+ const argExplainationString = `\n-# **${name}**: ${description}`
+ const choicesString =
+ 'choices' in option && option.choices
+ ? `\n\n-# **AVAILABLE CHOICES**\n${option.choices.map(({ value }) => `- ${value}`).join('\n')}`
+ : ''
+
+ if (isSubcommandLikeOption && !arg)
+ throw new CommandError(
+ CommandErrorType.MissingArgument,
+ `Missing required subcommand.\n\n-# **AVAILABLE SUBCOMMANDS**\n${iterableOptions.map(([name, { description }]) => `- **${name}**: ${description}`).join('\n')}`,
+ )
+
+ if (required && !arg)
+ throw new CommandError(
+ CommandErrorType.MissingArgument,
+ `Missing required argument **${name}** with type **${expectedType}**.${argExplainationString}${choicesString}`,
+ )
+
+ if (typeof arg === 'object' && arg.type !== type)
+ throw new CommandError(
+ CommandErrorType.InvalidArgument,
+ `Invalid type for argument **${name}**.${argExplainationString}\n\nExpected type: **${expectedType}**\nGot type: **${ApplicationCommandOptionType[arg.type]}**${choicesString}`,
+ )
+
+ const argValue = typeof arg === 'string' ? arg : arg?.id
+
+ if (
+ 'choices' in option &&
+ option.choices &&
+ !option.choices.some(({ value }) => value === (typeof value === 'number' ? Number(argValue) : argValue))
+ )
+ throw new CommandError(
+ CommandErrorType.InvalidArgument,
+ `Invalid choice for argument **${name}**.\n${argExplainationString}${choicesString}\n`,
+ )
+
+ if (argValue && arg) {
+ if (isSubcommandLikeOption) {
+ const [subcommandName, subcommandOption] = iterableOptions.find(([name]) => name === argValue)!
+
+ // @ts-expect-error: Not smart enough, TypeScript :(
+ _options[subcommandName] = await this.#resolveMessageOptions(
+ msg,
+ (subcommandOption as CommandSubcommandLikeOption).options,
+ args.slice(i + 1),
+ )
+
+ break
+ }
+
+ if (
+ type === ApplicationCommandOptionType.String &&
+ ((typeof option.minLength === 'number' && argValue.length < option.minLength) ||
+ (typeof option.maxLength === 'number' && argValue.length > option.maxLength))
+ )
+ throw new CommandError(
+ CommandErrorType.InvalidArgument,
+ `Invalid string length for argument **${name}**.\nLengths allowed: ${option.minLength ?? '(any)'} - ${option.maxLength ?? '(any)'}.${argExplainationString}`,
+ )
+
+ if (
+ (type === ApplicationCommandOptionType.Channel ||
+ type === ApplicationCommandOptionType.User ||
+ type === ApplicationCommandOptionType.Role) &&
+ Number.isNaN(Number(argValue))
+ )
+ throw new CommandError(
+ CommandErrorType.InvalidArgument,
+ `Malformed ID for argument **${name}**.${argExplainationString}`,
+ )
+
+ if (type === ApplicationCommandOptionType.Number || type === ApplicationCommandOptionType.Integer) {
+ if (Number.isNaN(Number(argValue)))
+ throw new CommandError(
+ CommandErrorType.InvalidArgument,
+ `Invalid number for argument **${name}**.${argExplainationString}`,
+ )
+
+ if (
+ (typeof option.min === 'number' && Number(argValue) < option.min) ||
+ (typeof option.max === 'number' && Number(argValue) > option.max)
+ )
+ throw new CommandError(
+ CommandErrorType.InvalidArgument,
+ `Number out of range for argument **${name}**.\nRange allowed: ${option.min ?? '(any)'} - ${option.max ?? '(any)'}.${argExplainationString}`,
+ )
+ }
+
+ if (
+ type === ApplicationCommandOptionType.Boolean &&
+ !['true', 'false', 'yes', 'no', 'y', 'n', 't', 'f'].includes(argValue)
+ )
+ throw new CommandError(
+ CommandErrorType.InvalidArgument,
+ `Invalid boolean for argument **${name}**.${argExplainationString}`,
+ )
+
+ // @ts-expect-error: Not smart enough, TypeScript :(
+ _options[name] =
+ type === ApplicationCommandOptionType.Number || type === ApplicationCommandOptionType.Integer
+ ? Number(argValue)
+ : type === ApplicationCommandOptionType.Boolean
+ ? ['t', 'y', 'yes', 'true'].some(value => value === argValue.toLowerCase())
+ : type === ApplicationCommandOptionType.Channel
+ ? await msg.client.channels.fetch(argValue)
+ : type === ApplicationCommandOptionType.User
+ ? await msg.client.users.fetch(argValue)
+ : type === ApplicationCommandOptionType.Role
+ ? await msg.guild?.roles.fetch(argValue)
+ : argValue
+ }
+ }
+
+ return _options
+ }
+
+ #fetchInteractionExecutor(interaction: CommandInteraction) {
+ return this.isGuildSpecific()
+ ? fetchMember(interaction as CommandInteraction<'raw' | 'cached'>)
+ : fetchUser(interaction)
+ }
+
+ async onInteraction(
+ context: typeof import('../context'),
+ interaction: ChatInputCommandInteraction,
+ ): Promise {
+ if (interaction.commandName !== this.name)
+ throw new CommandError(
+ CommandErrorType.InteractionDataMismatch,
+ 'The interaction command name does not match the expected command name.',
+ )
+
+ if (!this.isGuildSpecific() && !interaction.inGuild())
+ throw new CommandError(CommandErrorType.InteractionNotInGuild)
+
+ const executor = await this.#fetchInteractionExecutor(interaction)
+ if (!(await this.canExecute(executor))) throw new CommandError(CommandErrorType.RequirementsNotMet)
+
+ const options = this.options
+ ? ((await this.#resolveInteractionOptions(interaction)) as CommandExecuteFunctionOptionsParameter<
+ NonNullable
+ >)
+ : undefined
+
+ if (options === null)
+ throw new CommandError(
+ CommandErrorType.InteractionDataMismatch,
+ 'The registered interaction command option type does not match the expected command option type.',
+ )
+
+ // @ts-expect-error: Type mismatch (again!) because TypeScript is not smart enough
+ return await this.#execute({ ...context, executor }, interaction, options)
+ }
+
+ async #resolveInteractionOptions(
+ interaction: ChatInputCommandInteraction,
+ options: readonly CommandInteractionOption[] = interaction.options.data,
+ ) {
+ const _options = {} as unknown
+
+ if (this.options)
+ for (const { name, type, value } of options) {
+ if (this.options[name]?.type !== type) return null
+
+ if (
+ type === ApplicationCommandOptionType.Subcommand ||
+ type === ApplicationCommandOptionType.SubcommandGroup
+ ) {
+ const subOptions = Object.entries((this.options[name] as CommandSubcommandLikeOption).options)
+
+ // @ts-expect-error: Not smart enough, TypeScript :(
+ _options[name] = await this.#resolveInteractionOptions(interaction, subOptions)
+
+ break
+ }
+
+ if (!value) continue
+
+ // @ts-expect-error: Not smart enough, TypeScript :(
+ _options[name] =
+ type === ApplicationCommandOptionType.Channel
+ ? await interaction.client.channels.fetch(value as string)
+ : type === ApplicationCommandOptionType.User
+ ? await interaction.client.users.fetch(value as string)
+ : type === ApplicationCommandOptionType.Role
+ ? await interaction.guild?.roles.fetch(value as string)
+ : value
+ }
+
+ return _options
+ }
+
+ async canExecute(executor: User | GuildMember): Promise {
+ if (!this.requirements) return false
+
+ const isExecutorAdmin = isAdmin(executor)
+ if (isExecutorAdmin) return true
+
+ const {
+ adminOnly,
+ roles,
+ permissions,
+ users,
+ mode = 'all',
+ defaultCondition = 'fail',
+ memberRequirementsForUsers = 'pass',
+ } = this.requirements
+
+ const member = this.isGuildSpecific() ? (executor as GuildMember) : null
+ const boolDefaultCondition = defaultCondition !== 'fail'
+ const boolMemberRequirementsForUsers = memberRequirementsForUsers !== 'fail'
+
+ const conditions = [
+ adminOnly ? isExecutorAdmin : boolDefaultCondition,
+ users ? users.includes(executor.id) : boolDefaultCondition,
+ member
+ ? roles
+ ? roles.some(role => member.roles.cache.has(role))
+ : boolDefaultCondition
+ : boolMemberRequirementsForUsers,
+ member
+ ? permissions
+ ? member.permissions.has(permissions)
+ : boolDefaultCondition
+ : boolMemberRequirementsForUsers,
+ ]
+
+ if (mode === 'all' && conditions.some(condition => !condition)) return false
+ if (mode === 'any' && conditions.every(condition => !condition)) return false
+
+ return true
+ }
+
+ get json(): RESTPostAPIApplicationCommandsJSONBody {
+ // @ts-expect-error: I hate union types in TypeScript
+ const base: RESTPostAPIApplicationCommandsJSONBody = {
+ name: this.name,
+ type:
+ this.type === CommandType.ContextMenuGuildMessage || this.type === CommandType.ContextMenuMessage
+ ? ApplicationCommandType.Message
+ : this.type === CommandType.ContextMenuGuildMember || this.type === CommandType.ContextMenuUser
+ ? ApplicationCommandType.User
+ : ApplicationCommandType.ChatInput,
+ }
+
+ if (this.isContextMenuSpecific()) return base
+
+ return {
+ ...base,
+ description: this.description,
+ options: this.options ? this.#transformOptions(this.options) : undefined,
+ // https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-interaction-context-types
+ contexts: this.isGuildSpecific() ? [0] : [0, 1, 2],
+ } as RESTPostAPIChatInputApplicationCommandsJSONBody & { contexts: Array<0 | 1 | 2> }
+ }
+
+ #transformOptions(optionsObject: Record) {
+ const options: RESTPostAPIChatInputApplicationCommandsJSONBody['options'] = []
+
+ for (const [name, option] of Object.entries(optionsObject)) {
+ options.push({
+ // biome-ignore lint/suspicious/noExplicitAny: Good enough work here
+ type: option.type as any,
+ name,
+ description: option.description,
+ required: option.required,
+ ...(option.type === ApplicationCommandOptionType.Subcommand ||
+ option.type === ApplicationCommandOptionType.SubcommandGroup
+ ? {
+ options: this.#transformOptions((option as CommandSubcommandLikeOption).options),
+ }
+ : {}),
+ ...(option.type === ApplicationCommandOptionType.Channel ? { channel_types: option.types } : {}),
+ ...(option.type === ApplicationCommandOptionType.Integer ||
+ option.type === ApplicationCommandOptionType.Number
+ ? {
+ min_value: option.min,
+ max_value: option.max,
+ choices: option.choices,
+ autocomplete: option.autocomplete,
+ }
+ : {}),
+ ...(option.type === ApplicationCommandOptionType.String
+ ? {
+ min_length: option.minLength,
+ max_length: option.maxLength,
+ choices: option.choices,
+ autocomplete: option.autocomplete,
+ }
+ : {}),
+ })
+ }
+
+ return options
+ }
+}
+
+export class ModerationCommand<
+ Options extends CommandOptionsOptions,
+ AllowMessageCommand extends boolean = true,
+> extends Command {
+ constructor(options: ExtendedCommandOptions) {
+ super({
+ ...options,
+ requirements: {
+ ...options.requirements,
+ defaultCondition: 'pass',
+ roles: (config.moderation?.roles ?? []).concat(options.requirements?.roles ?? []),
+ },
+ // @ts-expect-error: No thanks
+ allowMessageCommand: options.allowMessageCommand ?? true,
+ type: CommandType.ChatGuild,
+ })
+ }
+}
+
+export class AdminCommand<
+ Options extends CommandOptionsOptions,
+ AllowMessageCommand extends boolean = true,
+> extends Command {
+ constructor(options: ExtendedCommandOptions) {
+ super({
+ ...options,
+ requirements: {
+ ...options.requirements,
+ adminOnly: true,
+ defaultCondition: 'pass',
+ },
+ allowMessageCommand: options.allowMessageCommand ?? (true as AllowMessageCommand),
+ type: CommandType.ChatGlobal,
+ })
+ }
+}
+
+const fetchMember = async (
+ interaction: CommandInteraction<'raw' | 'cached'>,
+ source: UserResolvable = interaction.user,
+ manager = interaction.guild?.members,
+) => {
+ const _manager = manager ?? (await interaction.client.guilds.fetch(interaction.guildId).then(it => it.members))
+ if (!_manager) throw new CommandError(CommandErrorType.FetchManagerNotFound, 'Cannot fetch member.')
+ return await _manager.fetch(source)
+}
+
+const fetchUser = (interaction: CommandInteraction, source: UserResolvable = interaction.user) => {
+ return interaction.client.users.fetch(source)
+}
+
+/* TODO:
+ APIApplicationCommandAttachmentOption
+ APIApplicationCommandMentionableOption
+ APIApplicationCommandRoleOption
+*/
+
+export type CommandOptions<
+ Type extends CommandType,
+ Options extends CommandOptionsOptions | undefined,
+ AllowMessageCommand extends boolean,
+> = {
+ name: string
+ requirements?: CommandRequirements
+ options?: Options
+ execute: CommandExecuteFunction
+ type?: Type
+ allowMessageCommand?: AllowMessageCommand
+} & If, { description?: never }, { description: string }>
+
+export type CommandArguments = Array
+export type CommandSpecialArgument = {
+ type: (typeof CommandSpecialArgumentType)[keyof typeof CommandSpecialArgumentType]
+ id: string
+}
+
+//! If things ever get minified, this will most likely break property access via string names
+export const CommandSpecialArgumentType = {
+ Channel: ApplicationCommandOptionType.Channel,
+ Role: ApplicationCommandOptionType.Role,
+ User: ApplicationCommandOptionType.User,
+}
+
+type ExtendedCommandOptions<
+ Type extends CommandType,
+ Options extends CommandOptionsOptions,
+ AllowMessageCommand extends boolean,
+> = Omit, 'type'> & {
+ requirements?: Omit['requirements'], 'defaultCondition'>
+}
+
+export type CommandOptionsOptions = Record
+
+type ToCacheType = If, 'raw' | 'cached', CacheType>
+
+type CommandExecuteFunction<
+ Type extends CommandType,
+ Options extends CommandOptionsOptions | undefined,
+ AllowMessageCommand extends boolean,
+> = (
+ context: CommandContext,
+ trigger: If<
+ AllowMessageCommand,
+ Message> | CommandTypeToInteractionMap>[Type],
+ CommandTypeToInteractionMap>[Type]
+ >,
+ options: Options extends CommandOptionsOptions ? CommandExecuteFunctionOptionsParameter : never,
+) => Promise | unknown
+
+type CommandTypeToInteractionMap = {
+ [CommandType.ChatGlobal]: ChatInputCommandInteraction
+ [CommandType.ChatGuild]: ChatInputCommandInteraction
+ [CommandType.ContextMenuUser]: UserContextMenuCommandInteraction
+ [CommandType.ContextMenuMessage]: MessageContextMenuCommandInteraction
+ [CommandType.ContextMenuGuildMessage]: MessageContextMenuCommandInteraction
+ [CommandType.ContextMenuGuildMember]: MessageContextMenuCommandInteraction
+}
+
+type IsContextMenu = Extends<
+ Type,
+ | CommandType.ContextMenuGuildMessage
+ | CommandType.ContextMenuGuildMember
+ | CommandType.ContextMenuMessage
+ | CommandType.ContextMenuUser
+>
+
+type IsGuildSpecific = Extends<
+ Type,
+ CommandType.ChatGuild | CommandType.ContextMenuGuildMember | CommandType.ContextMenuGuildMessage
+>
+
+type Extends = T extends U ? true : false
+type If = T extends true ? U : V
+// type InvertBoolean = If
+
+type CommandExecuteFunctionOptionsParameter = {
+ [K in keyof Options]: Options[K]['type'] extends
+ | ApplicationCommandOptionType.Subcommand
+ | ApplicationCommandOptionType.SubcommandGroup
+ ? // @ts-expect-error: Shut up, it works
+ CommandExecuteFunctionOptionsParameter | undefined
+ : If<
+ Options[K]['required'],
+ CommandOptionValueMap[Options[K]['type']],
+ CommandOptionValueMap[Options[K]['type']] | undefined
+ >
+}
+
+type CommandContext = typeof import('../context') & {
+ executor: CommandExecutor
+ target: If<
+ Extends,
+ GuildMember,
+ If, Message, never>
+ >
+}
+
+type CommandOptionValueMap = {
+ [ApplicationCommandOptionType.Boolean]: boolean
+ [ApplicationCommandOptionType.Channel]: Channel
+ [ApplicationCommandOptionType.Integer]: number
+ [ApplicationCommandOptionType.Number]: number
+ [ApplicationCommandOptionType.String]: string
+ [ApplicationCommandOptionType.User]: User
+ [ApplicationCommandOptionType.Role]: Role
+ [ApplicationCommandOptionType.Subcommand]: never
+ [ApplicationCommandOptionType.SubcommandGroup]: never
+}
+
+type CommandOption =
+ | CommandBooleanOption
+ | CommandChannelOption
+ | CommandIntegerOption
+ | CommandNumberOption
+ | CommandStringOption
+ | CommandUserOption
+ | CommandRoleOption
+ | CommandSubcommandOption
+ | CommandSubcommandGroupOption
+
+type CommandExecutor = If, GuildMember, User>
+
+type CommandOptionBase = {
+ type: Type
+ description: string
+ required?: boolean
+}
+
+type CommandBooleanOption = CommandOptionBase
+
+type CommandChannelOption = CommandOptionBase & {
+ types: APIApplicationCommandChannelOption['channel_types']
+}
+
+interface CommandOptionChoice {
+ name: string
+ value: ValueType
+}
+
+type CommandOptionWithAutocompleteOrChoicesWrapper<
+ Base extends CommandOptionBase,
+ ChoiceType extends CommandOptionChoice,
+> =
+ | (Base & {
+ autocomplete: true
+ choices?: never
+ })
+ | (Base & {
+ autocomplete?: false
+ choices?: ChoiceType[] | readonly ChoiceType[]
+ })
+
+type CommandIntegerOption = CommandOptionWithAutocompleteOrChoicesWrapper<
+ CommandOptionBase,
+ CommandOptionChoice
+> & {
+ min?: number
+ max?: number
+}
+
+type CommandNumberOption = CommandOptionWithAutocompleteOrChoicesWrapper<
+ CommandOptionBase,
+ CommandOptionChoice
+> & {
+ min?: number
+ max?: number
+}
+
+type CommandStringOption = CommandOptionWithAutocompleteOrChoicesWrapper<
+ CommandOptionBase,
+ CommandOptionChoice
+> & {
+ minLength?: number
+ maxLength?: number
+}
+
+type CommandUserOption = CommandOptionBase
+
+type CommandRoleOption = CommandOptionBase
+
+type SubcommandLikeApplicationCommandOptionType =
+ | ApplicationCommandOptionType.Subcommand
+ | ApplicationCommandOptionType.SubcommandGroup
+
+interface CommandSubcommandLikeOption<
+ Type extends SubcommandLikeApplicationCommandOptionType = SubcommandLikeApplicationCommandOptionType,
+> extends CommandOptionBase {
+ options: CommandOptionsOptions
+ required?: never
+}
+
+type CommandSubcommandOption = CommandSubcommandLikeOption
+type CommandSubcommandGroupOption = CommandSubcommandLikeOption
+
+export type CommandRequirements = {
+ users?: string[]
+ roles?: string[]
+ permissions?: bigint
+ adminOnly?: boolean
+ defaultCondition?: 'fail' | 'pass'
+ memberRequirementsForUsers?: 'fail' | 'pass'
+ mode?: 'all' | 'any'
+}
diff --git a/bots/discord/src/classes/CommandError.ts b/bots/discord/src/classes/CommandError.ts
new file mode 100644
index 0000000..94e9733
--- /dev/null
+++ b/bots/discord/src/classes/CommandError.ts
@@ -0,0 +1,48 @@
+import { createErrorEmbed } from '../utils/discord/embeds'
+
+export default class CommandError extends Error {
+ type: CommandErrorType
+
+ constructor(type: CommandErrorType, message: string = ErrorMessageMap[type]) {
+ super(message)
+ this.name = 'CommandError'
+ this.type = type
+ }
+
+ toEmbed() {
+ return createErrorEmbed(ErrorTitleMap[this.type], this.message ?? '')
+ }
+}
+
+export enum CommandErrorType {
+ Generic = 1,
+ InteractionNotInGuild,
+ InteractionDataMismatch,
+ FetchManagerNotFound,
+ FetchNotFound,
+ RequirementsNotMet = 100,
+ MissingArgument,
+ InvalidArgument,
+}
+
+const ErrorTitleMap: Record = {
+ [CommandErrorType.Generic]: 'An exception was thrown',
+ [CommandErrorType.InteractionNotInGuild]: 'This command can only be used in servers',
+ [CommandErrorType.InteractionDataMismatch]: 'Command data mismatch',
+ [CommandErrorType.FetchManagerNotFound]: 'Cannot fetch data (manager not found)',
+ [CommandErrorType.FetchNotFound]: 'Cannot fetch data (source not found)',
+ [CommandErrorType.RequirementsNotMet]: 'Command requirements not met',
+ [CommandErrorType.MissingArgument]: 'Missing argument',
+ [CommandErrorType.InvalidArgument]: 'Invalid argument',
+}
+
+const ErrorMessageMap: Record = {
+ [CommandErrorType.Generic]: 'An generic exception was thrown.',
+ [CommandErrorType.InteractionNotInGuild]: 'This command can only be used in servers.',
+ [CommandErrorType.InteractionDataMismatch]: 'Interaction command data does not match the expected command data.',
+ [CommandErrorType.FetchManagerNotFound]: 'Cannot fetch required data.',
+ [CommandErrorType.FetchNotFound]: 'Cannot fetch target.',
+ [CommandErrorType.RequirementsNotMet]: 'You do not meet the requirements to use this command.',
+ [CommandErrorType.MissingArgument]: 'You are missing a required argument.',
+ [CommandErrorType.InvalidArgument]: 'You provided an invalid argument.',
+}
diff --git a/bots/discord/src/commands/admin/eval.ts b/bots/discord/src/commands/admin/eval.ts
new file mode 100644
index 0000000..9205a63
--- /dev/null
+++ b/bots/discord/src/commands/admin/eval.ts
@@ -0,0 +1,95 @@
+import { unlinkSync, writeFileSync } from 'fs'
+import { join } from 'path'
+import { inspect } from 'util'
+import { createContext, runInContext } from 'vm'
+import { ApplicationCommandOptionType } from 'discord.js'
+
+import { AdminCommand } from '$/classes/Command'
+import { createSuccessEmbed } from '$/utils/discord/embeds'
+import { parseDuration } from '$/utils/duration'
+
+export default new AdminCommand({
+ name: 'eval',
+ description: 'Make the bot less sentient by evaluating code',
+ options: {
+ code: {
+ description: 'The code to evaluate',
+ type: ApplicationCommandOptionType.String,
+ required: true,
+ },
+ ['show-hidden']: {
+ description: 'Show hidden properties',
+ type: ApplicationCommandOptionType.Boolean,
+ required: false,
+ },
+ ['inspect-depth']: {
+ description: 'How many times to recurse while formatting the object (default: 1)',
+ type: ApplicationCommandOptionType.Integer,
+ required: false,
+ },
+ timeout: {
+ description: 'Timeout for the evaluation (default: 10s)',
+ type: ApplicationCommandOptionType.String,
+ required: false,
+ },
+ },
+ async execute(context, trigger, { code, 'show-hidden': showHidden, timeout, ['inspect-depth']: inspectDepth }) {
+ const currentToken = context.discord.client.token
+ const currentEnvToken = process.env['DISCORD_TOKEN']
+ context.discord.client.token = null
+ process.env['DISCORD_TOKEN'] = undefined
+
+ // This allows developers to access and modify the context object to apply changes
+ // to the bot while the bot is running, minus malicious actors getting the token to perform malicious actions
+ const output = await runInContext(
+ code,
+ createContext({
+ ...globalThis,
+ context,
+ trigger,
+ }),
+ {
+ timeout: parseDuration(timeout ?? '10s'),
+ filename: 'eval',
+ displayErrors: true,
+ },
+ )
+
+ context.discord.client.token = currentToken
+ process.env['DISCORD_TOKEN'] = currentEnvToken
+
+ const inspectedOutput = inspect(output, {
+ depth: inspectDepth ?? 1,
+ showHidden,
+ getters: showHidden,
+ numericSeparator: true,
+ showProxy: showHidden,
+ })
+
+ const embed = createSuccessEmbed('Evaluate', `\`\`\`js\n${code}\`\`\``)
+ const files: string[] = []
+ const filepath = join(Bun.main, '..', `output-eval-${Date.now()}.js`)
+
+ if (inspectedOutput.length > 1000) {
+ writeFileSync(filepath, inspectedOutput)
+ files.push(filepath)
+
+ embed.addFields({
+ name: 'Result',
+ value: '```js\n// (output too long, file uploaded)```',
+ })
+ } else
+ embed.addFields({
+ name: 'Result',
+ value: `\`\`\`js\n${inspectedOutput}\`\`\``,
+ })
+
+ await trigger.reply({
+ ephemeral: true,
+ embeds: [embed],
+ files,
+ })
+
+ if (files.length) unlinkSync(filepath)
+ },
+})
diff --git a/bots/discord/src/commands/admin/exception-test.ts b/bots/discord/src/commands/admin/exception-test.ts
new file mode 100644
index 0000000..a9017ca
--- /dev/null
+++ b/bots/discord/src/commands/admin/exception-test.ts
@@ -0,0 +1,24 @@
+import { ApplicationCommandOptionType } from 'discord.js'
+
+import { AdminCommand } from '$/classes/Command'
+import CommandError, { CommandErrorType } from '$/classes/CommandError'
+
+export default new AdminCommand({
+ name: 'exception-test',
+ description: 'Makes the bot intentionally hate you by throwing an exception',
+ options: {
+ type: {
+ description: 'The type of exception to throw',
+ type: ApplicationCommandOptionType.String,
+ required: true,
+ choices: [
+ { name: 'Process', value: 'Process' },
+ ...Object.keys(CommandErrorType).map(k => ({ name: k, value: k })),
+ ],
+ },
+ },
+ async execute(_, __, { type }) {
+ if (type === 'Process') throw new Error('Intentional process exception')
+ throw new CommandError(CommandErrorType[type as keyof typeof CommandErrorType], 'Intentional bot design') // ;)
+ },
+})
diff --git a/bots/discord/src/commands/admin/reload.ts b/bots/discord/src/commands/admin/reload.ts
new file mode 100644
index 0000000..d7e66e9
--- /dev/null
+++ b/bots/discord/src/commands/admin/reload.ts
@@ -0,0 +1,37 @@
+import { AdminCommand } from '$/classes/Command'
+
+export default new AdminCommand({
+ name: 'reload',
+ description: 'Reload configuration',
+ async execute(context, trigger) {
+ const { api, logger, discord } = context
+ logger.info(`Reload triggered by ${context.executor.tag} (${context.executor.id})`)
+
+ logger.debug('Invalidating previous config...')
+ context.config.invalidate()
+
+ if ('deferReply' in trigger) await trigger.deferReply({ ephemeral: true })
+
+ logger.info('Reinitializing API client to reload configuration...')
+ await api.client.ws.setOptions(
+ {
+ url: context.config.api.url,
+ },
+ false,
+ )
+ api.intentionallyDisconnecting = true
+ api.client.disconnect(true)
+ api.disconnectCount = 0
+ api.intentionallyDisconnecting = false
+ api.client.connect()
+
+ logger.info('Reinitializing Discord client to reload configuration...')
+ await discord.client.destroy()
+ // discord.client.token only gets set whenever a new Client is intialized
+ // so that's why we need to provide the token here :/
+ await discord.client.login(process.env['DISCORD_TOKEN'])
+
+ // @ts-expect-error: TypeScript dum
+ await trigger['deferReply' in trigger ? 'editReply' : 'reply']({ content: 'Reloaded configuration' })
+ },
+})
diff --git a/bots/discord/src/commands/admin/slash-commands.ts b/bots/discord/src/commands/admin/slash-commands.ts
new file mode 100644
index 0000000..9970ac4
--- /dev/null
+++ b/bots/discord/src/commands/admin/slash-commands.ts
@@ -0,0 +1,93 @@
+import { ApplicationCommandOptionType, Routes } from 'discord.js'
+
+import { AdminCommand } from '$/classes/Command'
+import CommandError, { CommandErrorType } from '$/classes/CommandError'
+
+import { createSuccessEmbed } from '$/utils/discord/embeds'
+
+const SubcommandOptions = {
+ where: {
+ description: 'Where to register the commands',
+ type: ApplicationCommandOptionType.String,
+ choices: [
+ { name: 'globally', value: 'global' },
+ { name: 'this server', value: 'server' },
+ ],
+ required: true,
+ },
+} as const
+
+export default new AdminCommand({
+ name: 'slash-commands',
+ description: 'Register or delete slash commands',
+ options: {
+ register: {
+ description: 'Register slash commands',
+ type: ApplicationCommandOptionType.Subcommand,
+ options: SubcommandOptions,
+ },
+ delete: {
+ description: 'Delete slash commands',
+ type: ApplicationCommandOptionType.Subcommand,
+ options: SubcommandOptions,
+ },
+ },
+ allowMessageCommand: true,
+ async execute(context, trigger, { delete: deleteOption, register }) {
+ const action = register ? 'register' : 'delete'
+ const { where } = (deleteOption ?? register)!
+
+ if (!trigger.inGuild())
+ throw new CommandError(CommandErrorType.Generic, 'This command can only be used in a server.')
+
+ const { global: globalCommands, guild: guildCommands } = Object.groupBy(
+ Object.values(context.discord.commands),
+ cmd => (cmd.isGuildSpecific() ? 'guild' : 'global'),
+ )
+
+ const {
+ client,
+ client: { rest },
+ } = trigger
+
+ let response: string | undefined
+
+ switch (action) {
+ case 'register':
+ if (where === 'global') {
+ response = 'Registered global slash commands'
+
+ await rest.put(Routes.applicationCommands(client.application.id), {
+ body: globalCommands?.map(c => c.json),
+ })
+ } else {
+ response = 'Registered slash commands on this server'
+
+ await rest.put(Routes.applicationGuildCommands(client.application.id, trigger.guildId), {
+ body: guildCommands?.map(c => c.json),
+ })
+ }
+
+ break
+
+ case 'delete':
+ if (where === 'global') {
+ response = 'Deleted global slash commands'
+
+ await rest.put(Routes.applicationCommands(client.application.id), {
+ body: [],
+ })
+ } else {
+ response = 'Deleted slash commands on this server'
+
+ await rest.put(Routes.applicationGuildCommands(client.application.id, trigger.guildId), {
+ body: [],
+ })
+ }
+
+ break
+ }
+
+ await trigger.reply({ embeds: [createSuccessEmbed(response!)] })
+ },
+})
diff --git a/bots/discord/src/commands/admin/stop.ts b/bots/discord/src/commands/admin/stop.ts
new file mode 100644
index 0000000..e4dd6c7
--- /dev/null
+++ b/bots/discord/src/commands/admin/stop.ts
@@ -0,0 +1,24 @@
+import { AdminCommand } from '$/classes/Command'
+
+export default new AdminCommand({
+ name: 'stop',
+ description: "You don't want to run this unless the bot starts to go insane, and like, you really need to stop it.",
+ async execute({ api, logger, executor }, trigger) {
+ api.intentionallyDisconnecting = true
+
+ logger.fatal('Stopping bot...')
+ trigger.reply({
+ content: 'Stopping... (I will go offline once done)',
+ ephemeral: true,
+ })
+
+ if (!api.client.disconnected) api.client.disconnect()
+ logger.warn('Disconnected from API')
+
+ trigger.client.destroy()
+ logger.warn('Disconnected from Discord API')
+
+ logger.info(`Bot stopped, requested by ${executor.id}`)
+ process.exit(0)
+ },
+})
diff --git a/bots/discord/src/commands/fun/coinflip.ts b/bots/discord/src/commands/fun/coinflip.ts
new file mode 100644
index 0000000..ec0b341
--- /dev/null
+++ b/bots/discord/src/commands/fun/coinflip.ts
@@ -0,0 +1,39 @@
+import { EmbedBuilder } from 'discord.js'
+
+import Command from '$/classes/Command'
+import { applyCommonEmbedStyles } from '$/utils/discord/embeds'
+
+export default new Command({
+ name: 'coinflip',
+ description: 'Do a coinflip!',
+ type: Command.Type.ChatGlobal,
+ requirements: {
+ defaultCondition: 'pass',
+ },
+ allowMessageCommand: true,
+ async execute(_, trigger) {
+ const result = Math.random() < 0.5 ? ('heads' as const) : ('tails' as const)
+ const embed = applyCommonEmbedStyles(new EmbedBuilder().setTitle('Flipping... 🪙'), false, false, true)
+
+ const reply = await trigger
+ .reply({
+ embeds: [embed.toJSON()],
+ })
+ .then(it => it.fetch())
+
+ embed.setTitle(`The coin landed on... **${result.toUpperCase()}**! ${EmojiMap[result]}`)
+
+ setTimeout(
+ () =>
+ reply.edit({
+ embeds: [embed.toJSON()],
+ }),
+ 1500,
+ )
+ },
+})
+
+const EmojiMap: Record<'heads' | 'tails', string> = {
+ heads: '🤯',
+ tails: '🐈',
+}
diff --git a/bots/discord/src/commands/fun/reply.ts b/bots/discord/src/commands/fun/reply.ts
new file mode 100644
index 0000000..69a3def
--- /dev/null
+++ b/bots/discord/src/commands/fun/reply.ts
@@ -0,0 +1,46 @@
+import CommandError, { CommandErrorType } from '$/classes/CommandError'
+import { ApplicationCommandOptionType, Message } from 'discord.js'
+import { ModerationCommand } from '../../classes/Command'
+
+export default new ModerationCommand({
+ name: 'reply',
+ description: 'Send a message as the bot',
+ options: {
+ message: {
+ description: 'The message to send',
+ required: true,
+ type: ApplicationCommandOptionType.String,
+ },
+ reference: {
+ description: 'The message ID to reply to (use `latest` to reply to the latest message)',
+ required: false,
+ type: ApplicationCommandOptionType.String,
+ },
+ },
+ allowMessageCommand: false,
+ async execute({ logger, executor }, trigger, { reference: ref, message: msg }) {
+ if (trigger instanceof Message) return
+
+ const channel = await trigger.guild!.channels.fetch(trigger.channelId)
+ if (!channel?.isTextBased())
+ throw new CommandError(
+ CommandErrorType.InvalidArgument,
+ 'This command can only be used in or on text channels',
+ )
+ const refMsg = ref?.startsWith('latest')
+ ? await channel.messages.fetch({ limit: 1 }).then(it => it.first())
+ : ref
+
+ await channel.send({
+ content: msg,
+ reply: refMsg ? { messageReference: refMsg, failIfNotExists: true } : undefined,
+ })
+
+ logger.info(`User ${executor.user.tag} made the bot say: ${msg}`)
+
+ await trigger.reply({
+ content: 'OK!',
+ ephemeral: true,
+ })
+ },
+})
diff --git a/bots/discord/src/commands/moderation/ban.ts b/bots/discord/src/commands/moderation/ban.ts
new file mode 100644
index 0000000..c664519
--- /dev/null
+++ b/bots/discord/src/commands/moderation/ban.ts
@@ -0,0 +1,59 @@
+import { ModerationCommand } from '$/classes/Command'
+import CommandError, { CommandErrorType } from '$/classes/CommandError'
+import { createModerationActionEmbed } from '$/utils/discord/embeds'
+import { sendModerationReplyAndLogs } from '$/utils/discord/moderation'
+import { parseDuration } from '$/utils/duration'
+
+export default new ModerationCommand({
+ name: 'ban',
+ description: 'Ban a user',
+ options: {
+ user: {
+ description: 'The user to ban',
+ required: true,
+ type: ModerationCommand.OptionType.User,
+ },
+ reason: {
+ description: 'The reason for banning the user',
+ required: false,
+ type: ModerationCommand.OptionType.String,
+ },
+ dmt: {
+ description:
+ 'Time duration to delete messages (default time unit is days, must be from 0s to 7d, default is 0s)',
+ required: false,
+ type: ModerationCommand.OptionType.String,
+ },
+ },
+ async execute({ logger, executor }, interaction, { user, reason, dmt }) {
+ const guild = await interaction.client.guilds.fetch(interaction.guildId)
+ const member = await guild.members.fetch(user).catch(() => {})
+ const moderator = await guild.members.fetch(executor.user)
+
+ if (member) {
+ if (!member.bannable)
+ throw new CommandError(CommandErrorType.Generic, 'This user cannot be banned by the bot.')
+
+ if (moderator.roles.highest.comparePositionTo(member.roles.highest) <= 0)
+ throw new CommandError(
+ CommandErrorType.InvalidArgument,
+ 'You cannot ban a user with a role equal to or higher than yours.',
+ )
+ }
+
+ const dms = Math.floor((dmt ? parseDuration(dmt, 'd') : 0) / 1000)
+ await interaction.guild!.members.ban(user, {
+ reason: `Banned by moderator ${executor.user.tag} (${executor.id}): ${reason}`,
+ deleteMessageSeconds: dms,
+ })
+
+ await sendModerationReplyAndLogs(
+ interaction,
+ createModerationActionEmbed('Banned', user, executor.user, reason),
+ )
+
+ logger.info(
+ `${executor.user.tag} (${executor.id}) banned ${user.tag} (${user.id}) because ${reason}, deleting their messages sent in the previous ${dms}s`,
+ )
+ },
+})
diff --git a/bots/discord/src/commands/moderation/cure.ts b/bots/discord/src/commands/moderation/cure.ts
new file mode 100644
index 0000000..15b144e
--- /dev/null
+++ b/bots/discord/src/commands/moderation/cure.ts
@@ -0,0 +1,24 @@
+import { ModerationCommand } from '$/classes/Command'
+import { createSuccessEmbed } from '$/utils/discord/embeds'
+import { cureNickname } from '$/utils/discord/moderation'
+
+export default new ModerationCommand({
+ name: 'cure',
+ description: "Cure a member's nickname",
+ options: {
+ member: {
+ description: 'The member to cure',
+ required: true,
+ type: ModerationCommand.OptionType.User,
+ },
+ },
+ async execute(_, interaction, { member: user }) {
+ const guild = await interaction.client.guilds.fetch(interaction.guildId)
+ const member = await guild.members.fetch(user)
+ await cureNickname(member)
+ await interaction.reply({
+ embeds: [createSuccessEmbed(null, `Cured nickname for ${member.toString()}`)],
+ ephemeral: true,
+ })
+ },
+})
diff --git a/bots/discord/src/commands/moderation/mute.ts b/bots/discord/src/commands/moderation/mute.ts
new file mode 100644
index 0000000..1e34236
--- /dev/null
+++ b/bots/discord/src/commands/moderation/mute.ts
@@ -0,0 +1,75 @@
+import { ModerationCommand } from '$/classes/Command'
+import CommandError, { CommandErrorType } from '$/classes/CommandError'
+import { createModerationActionEmbed } from '$/utils/discord/embeds'
+import { sendModerationReplyAndLogs } from '$/utils/discord/moderation'
+import { applyRolePreset, removeRolePreset } from '$/utils/discord/rolePresets'
+import { parseDuration } from '$/utils/duration'
+
+export default new ModerationCommand({
+ name: 'mute',
+ description: 'Mute a member',
+ options: {
+ member: {
+ description: 'The member to mute',
+ required: true,
+ type: ModerationCommand.OptionType.User,
+ },
+ duration: {
+ description: 'The duration of the mute (default time unit is minutes)',
+ required: false,
+ type: ModerationCommand.OptionType.String,
+ },
+ reason: {
+ description: 'The reason for muting the member',
+ required: false,
+ type: ModerationCommand.OptionType.String,
+ },
+ },
+ async execute(
+ { logger, executor },
+ interaction,
+ { member: user, reason = 'No reason provided', duration: durationInput },
+ ) {
+ const guild = await interaction.client.guilds.fetch(interaction.guildId)
+ const member = await guild.members.fetch(user.id)
+ const moderator = await guild.members.fetch(executor.id)
+ const duration = durationInput ? parseDuration(durationInput, 'm') : Infinity
+
+ if (Number.isInteger(duration) && duration! < 1)
+ throw new CommandError(
+ CommandErrorType.InvalidArgument,
+ 'The duration must be at least 1 millisecond long.',
+ )
+
+ const expires = Math.max(duration, Date.now() + duration)
+ if (!member)
+ throw new CommandError(
+ CommandErrorType.InvalidArgument,
+ 'The provided member is not in the server or does not exist.',
+ )
+
+ if (!member.manageable)
+ throw new CommandError(CommandErrorType.Generic, 'This user cannot be managed by the bot.')
+
+ if (moderator.roles.highest.comparePositionTo(member.roles.highest) <= 0)
+ throw new CommandError(
+ CommandErrorType.InvalidArgument,
+ 'You cannot mute a user with a role equal to or higher than yours.',
+ )
+
+ await applyRolePreset(member, 'mute', expires)
+ await sendModerationReplyAndLogs(
+ interaction,
+ createModerationActionEmbed('Muted', user, executor.user, reason, Math.ceil(expires / 1000)),
+ )
+
+ if (duration)
+ setTimeout(() => {
+ removeRolePreset(member, 'mute')
+ }, duration)
+
+ logger.info(
+ `Moderator ${executor.user.tag} (${executor.user.id}) muted ${user.tag} (${user.id}) until ${expires} because ${reason}`,
+ )
+ },
+})
diff --git a/bots/discord/src/commands/moderation/purge.ts b/bots/discord/src/commands/moderation/purge.ts
new file mode 100644
index 0000000..dc218d0
--- /dev/null
+++ b/bots/discord/src/commands/moderation/purge.ts
@@ -0,0 +1,69 @@
+import { EmbedBuilder } from 'discord.js'
+
+import { ModerationCommand } from '$/classes/Command'
+import CommandError, { CommandErrorType } from '$/classes/CommandError'
+import { applyCommonEmbedStyles } from '$/utils/discord/embeds'
+
+export default new ModerationCommand({
+ name: 'purge',
+ description: 'Purge messages from a channel',
+ options: {
+ amount: {
+ description: 'The amount of messages to remove',
+ required: false,
+ type: ModerationCommand.OptionType.Integer,
+ min: 1,
+ max: 100,
+ },
+ user: {
+ description: 'The user to remove messages from (needs `until`)',
+ required: false,
+ type: ModerationCommand.OptionType.User,
+ },
+ until: {
+ description: 'The message ID to remove messages until (overrides `amount`)',
+ required: false,
+ type: ModerationCommand.OptionType.String,
+ },
+ },
+ async execute({ logger, executor }, interaction, { amount, user, until }) {
+ if (!amount && !until)
+ throw new CommandError(CommandErrorType.MissingArgument, 'Either `amount` or `until` must be provided.')
+
+ const channel = interaction.channel!
+ if (!channel.isTextBased())
+ throw new CommandError(CommandErrorType.InvalidArgument, 'The supplied channel is not a text channel.')
+
+ const embed = applyCommonEmbedStyles(
+ new EmbedBuilder({
+ title: 'Purging messages',
+ description: 'Accumulating messages...',
+ }),
+ true,
+ true,
+ true,
+ )
+
+ const msgsPromise = channel.messages.fetch(until ? { after: until } : { limit: amount! })
+ const reply = await interaction.reply({ embeds: [embed] }).then(it => it.fetch())
+
+ const messages = (
+ user ? (await msgsPromise).filter(msg => msg.author.id === user.id) : await msgsPromise
+ ).filter(msg => msg.id !== reply.id)
+
+ await channel.bulkDelete(messages, true)
+
+ logger.info(
+ `Moderator ${executor.user.tag} (${executor.id}) purged ${messages.size} messages in #${channel.name} (${channel.id})`,
+ )
+
+ await reply.edit({
+ embeds: [
+ embed.setTitle('Purged messages').setDescription(null).addFields({
+ name: 'Deleted messages',
+ value: messages.size.toString(),
+ }),
+ ],
+ })
+ },
+})
diff --git a/bots/discord/src/commands/moderation/role-preset.ts b/bots/discord/src/commands/moderation/role-preset.ts
new file mode 100644
index 0000000..9e9f689
--- /dev/null
+++ b/bots/discord/src/commands/moderation/role-preset.ts
@@ -0,0 +1,95 @@
+import { ModerationCommand } from '$/classes/Command'
+import CommandError, { CommandErrorType } from '$/classes/CommandError'
+import { sendPresetReplyAndLogs } from '$/utils/discord/moderation'
+import { applyRolePreset, removeRolePreset } from '$/utils/discord/rolePresets'
+import { parseDuration } from '$/utils/duration'
+
+const SubcommandOptions = {
+ member: {
+ description: 'The member to manage',
+ required: true,
+ type: ModerationCommand.OptionType.User,
+ },
+ preset: {
+ description: 'The preset to manage',
+ required: true,
+ type: ModerationCommand.OptionType.String,
+ },
+ duration: {
+ description: 'The duration to apply the preset for (only for apply action, default time unit is minutes)',
+ required: false,
+ type: ModerationCommand.OptionType.String,
+ },
+} as const
+
+export default new ModerationCommand({
+ name: 'role-preset',
+ description: 'Manage role presets for a member',
+ options: {
+ apply: {
+ description: 'Apply a role preset to a member',
+ type: ModerationCommand.OptionType.Subcommand,
+ options: SubcommandOptions,
+ },
+ remove: {
+ description: 'Remove a role preset from a member',
+ type: ModerationCommand.OptionType.Subcommand,
+ options: SubcommandOptions,
+ },
+ },
+ async execute({ logger, executor }, trigger, { apply, remove }) {
+ let expires: number | undefined
+ const { member: user, duration: durationInput, preset } = (apply ?? remove)!
+ const moderator = await trigger.guild!.members.fetch(executor.user.id)
+ const member = await trigger.guild!.members.fetch(user.id)
+
+ if (!member)
+ throw new CommandError(
+ CommandErrorType.InvalidArgument,
+ 'The provided member is not in the server or does not exist.',
+ )
+
+ if (!member.manageable)
+ throw new CommandError(CommandErrorType.Generic, 'This user cannot be managed by the bot.')
+
+ if (apply) {
+ const duration = durationInput ? parseDuration(durationInput, 'm') : Infinity
+ if (Number.isInteger(duration) && duration! < 1)
+ throw new CommandError(
+ CommandErrorType.InvalidArgument,
+ 'The duration must be at least 1 millisecond long.',
+ )
+
+ if (moderator.roles.highest.comparePositionTo(member.roles.highest) <= 0)
+ throw new CommandError(
+ CommandErrorType.InvalidArgument,
+ 'You cannot apply a role preset to a user with a role equal to or higher than yours.',
+ )
+
+ expires = Math.max(duration, Date.now() + duration)
+ await applyRolePreset(member, preset, expires)
+ logger.info(
+ `Moderator ${executor.user.tag} (${executor.user.id}) applied role preset ${preset} to ${user.id} until ${expires}`,
+ )
+ } else if (remove) {
+ await removeRolePreset(member, preset)
+ logger.info(
+ `Moderator ${executor.user.tag} (${executor.user.id}) removed role preset ${preset} from ${user.id}`,
+ )
+ }
+
+ if (expires)
+ setTimeout(() => {
+ removeRolePreset(member, preset)
+ }, expires)
+
+ await sendPresetReplyAndLogs(
+ apply ? 'apply' : 'remove',
+ trigger,
+ executor,
+ user,
+ preset,
+ expires ? Math.ceil(expires / 1000) : undefined,
+ )
+ },
+})
diff --git a/bots/discord/src/commands/moderation/slowmode.ts b/bots/discord/src/commands/moderation/slowmode.ts
new file mode 100644
index 0000000..b6a43a9
--- /dev/null
+++ b/bots/discord/src/commands/moderation/slowmode.ts
@@ -0,0 +1,51 @@
+import { createSuccessEmbed } from '$/utils/discord/embeds'
+import { durationToString, parseDuration } from '$/utils/duration'
+
+import { ModerationCommand } from '$/classes/Command'
+import CommandError, { CommandErrorType } from '$/classes/CommandError'
+import { ChannelType } from 'discord.js'
+
+export default new ModerationCommand({
+ name: 'slowmode',
+ description: 'Set a slowmode for a channel',
+ options: {
+ duration: {
+ description: 'The duration to set (default time unit is seconds)',
+ required: true,
+ type: ModerationCommand.OptionType.String,
+ },
+ channel: {
+ description: 'The channel to set the slowmode on (defaults to current channel)',
+ required: false,
+ type: ModerationCommand.OptionType.Channel,
+ types: [ChannelType.GuildText],
+ },
+ },
+ async execute({ logger, executor }, interaction, { duration: durationInput, channel: channelInput }) {
+ const channel = channelInput ?? (await interaction.guild!.channels.fetch(interaction.channelId))
+ const duration = parseDuration(durationInput, 's')
+
+ if (!channel?.isTextBased() || channel.isDMBased())
+ throw new CommandError(CommandErrorType.InvalidArgument, 'The supplied channel is not a text channel.')
+
+ if (Number.isNaN(duration)) throw new CommandError(CommandErrorType.InvalidArgument, 'Invalid duration.')
+ if (duration < 0 || duration > 36e4)
+ throw new CommandError(
+ CommandErrorType.InvalidArgument,
+ 'Duration out of range, must be between 0s and 6h.',
+ )
+
+ await channel.setRateLimitPerUser(duration / 1000, `Set by ${executor.user.tag} (${executor.id})`)
+ await interaction.reply({
+ embeds: [
+ createSuccessEmbed(
+ `Slowmode ${duration ? `set to ${durationToString(duration)}` : 'removed'} on ${channel.toString()}`,
+ ),
+ ],
+ })
+
+ logger.info(
+ `${executor.user.tag} (${executor.id}) set the slowmode on ${channel.name} (${channel.id}) to ${duration}ms`,
+ )
+ },
+})
diff --git a/bots/discord/src/commands/moderation/unban.ts b/bots/discord/src/commands/moderation/unban.ts
new file mode 100644
index 0000000..c0c86f7
--- /dev/null
+++ b/bots/discord/src/commands/moderation/unban.ts
@@ -0,0 +1,21 @@
+import { ModerationCommand } from '$/classes/Command'
+import { createModerationActionEmbed } from '$/utils/discord/embeds'
+import { sendModerationReplyAndLogs } from '$/utils/discord/moderation'
+
+export default new ModerationCommand({
+ name: 'unban',
+ description: 'Unban a user',
+ options: {
+ user: {
+ description: 'The user to unban',
+ required: true,
+ type: ModerationCommand.OptionType.User,
+ },
+ },
+ async execute({ logger, executor }, interaction, { user }) {
+ await interaction.guild!.members.unban(user, `Unbanned by moderator ${executor.user.tag} (${executor.id})`)
+
+ await sendModerationReplyAndLogs(interaction, createModerationActionEmbed('Unbanned', user, executor.user))
+ logger.info(`${executor.user.tag} (${executor.id}) unbanned ${user.tag} (${user.id})`)
+ },
+})
diff --git a/bots/discord/src/commands/moderation/unmute.ts b/bots/discord/src/commands/moderation/unmute.ts
new file mode 100644
index 0000000..d45db30
--- /dev/null
+++ b/bots/discord/src/commands/moderation/unmute.ts
@@ -0,0 +1,39 @@
+import { ModerationCommand } from '$/classes/Command'
+import CommandError, { CommandErrorType } from '$/classes/CommandError'
+import { appliedPresets } from '$/database/schemas'
+import { createModerationActionEmbed } from '$/utils/discord/embeds'
+import { sendModerationReplyAndLogs } from '$/utils/discord/moderation'
+import { removeRolePreset } from '$/utils/discord/rolePresets'
+import { and, eq } from 'drizzle-orm'
+
+export default new ModerationCommand({
+ name: 'unmute',
+ description: 'Unmute a member',
+ options: {
+ member: {
+ description: 'The member to unmute',
+ required: true,
+ type: ModerationCommand.OptionType.User,
+ },
+ },
+ async execute({ logger, database, executor }, interaction, { member: user }) {
+ const member = await interaction.guild!.members.fetch(user.id)
+ if (!member)
+ throw new CommandError(
+ CommandErrorType.InvalidArgument,
+ 'The provided member is not in the server or does not exist.',
+ )
+
+ if (
+ !(await database.query.appliedPresets.findFirst({
+ where: and(eq(appliedPresets.memberId, member.id), eq(appliedPresets.preset, 'mute')),
+ }))
+ )
+ throw new CommandError(CommandErrorType.Generic, 'This user is not muted.')
+
+ await removeRolePreset(member, 'mute')
+ await sendModerationReplyAndLogs(interaction, createModerationActionEmbed('Unmuted', user, executor.user))
+
+ logger.info(`Moderator ${executor.user.tag} (${executor.id}) unmuted ${user.tag} (${user.id})`)
+ },
+})
diff --git a/bots/discord/src/commands/support/train/chat.ts b/bots/discord/src/commands/support/train/chat.ts
new file mode 100644
index 0000000..45ae34c
--- /dev/null
+++ b/bots/discord/src/commands/support/train/chat.ts
@@ -0,0 +1,76 @@
+import Command from '$/classes/Command'
+import CommandError, { CommandErrorType } from '$/classes/CommandError'
+import { createSuccessEmbed } from '$/utils/discord/embeds'
+import type { ConfigMessageScanResponseLabelConfig } from 'config.schema'
+import type { FetchMessageOptions, MessageResolvable } from 'discord.js'
+import { config } from '../../../context'
+
+const msRcConfig = config.messageScan?.humanCorrections?.allow
+
+export default new Command({
+ name: 'train',
+ description: 'Train a specific message or text to a specific label',
+ type: Command.Type.ChatGuild,
+ requirements: {
+ users: msRcConfig?.users,
+ roles: msRcConfig?.members?.roles,
+ permissions: msRcConfig?.members?.permissions,
+ mode: 'any',
+ memberRequirementsForUsers: 'fail',
+ defaultCondition: 'fail',
+ },
+ options: {
+ message: {
+ description: 'The message to train (use `latest` to train the latest message)',
+ type: Command.OptionType.String,
+ required: true,
+ },
+ label: {
+ description: 'The label to train the message as',
+ type: Command.OptionType.String,
+ required: true,
+ },
+ },
+ allowMessageCommand: true,
+ async execute(context, trigger, { label, message: ref }) {
+ const { logger, config } = context
+ const { messageScan: msConfig } = config
+
+ // If there's no config, we can't do anything
+ if (!msConfig?.humanCorrections) throw new CommandError(CommandErrorType.Generic, 'Response correction is off.')
+ const labels = msConfig.responses?.flatMap(r =>
+ r.triggers.text!.filter((t): t is ConfigMessageScanResponseLabelConfig => 'label' in t).map(t => t.label),
+ )
+
+ const channel = await trigger.guild!.channels.fetch(trigger.channelId)
+ if (!channel?.isTextBased())
+ throw new CommandError(
+ CommandErrorType.InvalidArgument,
+ 'This command can only be used in or on text channels',
+ )
+
+ if (!labels.includes(label))
+ throw new CommandError(
+ CommandErrorType.InvalidArgument,
+ `The provided label is invalid.\nValid labels are:${labels.map(l => `\n- \`${l}\``).join('')}`,
+ )
+
+ const refMsg = await channel.messages.fetch(
+ (ref.startsWith('latest') ? { limit: 1 } : ref) as MessageResolvable | FetchMessageOptions,
+ )
+ if (!refMsg) throw new CommandError(CommandErrorType.InvalidArgument, 'The provided message does not exist.')
+
+ logger.debug(`User ${context.executor.id} is training message ${refMsg?.id} as ${label}`)
+
+ await context.api.client.trainMessage(refMsg.content, label)
+ await trigger.reply({
+ embeds: [
+ createSuccessEmbed(
+ 'Message trained',
+ `The provided message has been trained as \`${label}\`. Thank you for your contribution!`,
+ ),
+ ],
+ ephemeral: true,
+ })
+ },
+})
diff --git a/bots/discord/src/commands/support/train/context-menu.ts b/bots/discord/src/commands/support/train/context-menu.ts
new file mode 100644
index 0000000..cb343cd
--- /dev/null
+++ b/bots/discord/src/commands/support/train/context-menu.ts
@@ -0,0 +1,50 @@
+import Command from '$/classes/Command'
+import CommandError, { CommandErrorType } from '$/classes/CommandError'
+import type { ConfigMessageScanResponseLabelConfig } from 'config.schema'
+import { type APIStringSelectComponent, ComponentType } from 'discord.js'
+import { config } from '../../../context'
+
+const msRcConfig = config.messageScan?.humanCorrections?.allow
+
+export default new Command({
+ name: 'Train Message',
+ type: Command.Type.ContextMenuGuildMessage,
+ requirements: {
+ users: msRcConfig?.users,
+ roles: msRcConfig?.members?.roles,
+ permissions: msRcConfig?.members?.permissions,
+ mode: 'any',
+ memberRequirementsForUsers: 'fail',
+ defaultCondition: 'fail',
+ },
+ async execute(context, trigger) {
+ const { logger, config } = context
+ const { messageScan: msConfig } = config
+
+ // If there's no config, we can't do anything
+ if (!msConfig?.humanCorrections) throw new CommandError(CommandErrorType.Generic, 'Response correction is off.')
+
+ logger.debug(`User ${context.executor.id} is training message ${trigger.targetId}`)
+
+ const labels = msConfig.responses.flatMap(r =>
+ r.triggers.text!.filter((t): t is ConfigMessageScanResponseLabelConfig => 'label' in t).map(t => t.label),
+ )
+
+ await trigger.reply({
+ content: 'Select a label to train this message as:',
+ components: [
+ {
+ components: [
+ {
+ custom_id: `tr_${trigger.targetMessage.channelId}_${trigger.targetId}`,
+ options: labels.map(label => ({ label, value: label })),
+ type: ComponentType.StringSelect,
+ } satisfies APIStringSelectComponent,
+ ],
+ type: ComponentType.ActionRow,
+ },
+ ],
+ ephemeral: true,
+ })
+ },
+})
diff --git a/bots/discord/src/config.ts b/bots/discord/src/config.ts
new file mode 100644
index 0000000..d308eef
--- /dev/null
+++ b/bots/discord/src/config.ts
@@ -0,0 +1,28 @@
+import { dirname, join } from 'path'
+import _firstConfig from '../config.js'
+
+let currentConfig = _firstConfig
+
+// Other parts of the code will access properties of this proxy, they don't care what the target looks like
+export const config = new Proxy(
+ {
+ INSPECTION_WARNING: 'Run `context.__getConfig()` to inspect the latest config.',
+ } as unknown as typeof currentConfig,
+ {
+ get(_, p, receiver) {
+ if (p === 'invalidate')
+ return async () => {
+ const path = join(dirname(Bun.main), '..', 'config.js')
+ Loader.registry.delete(path)
+ currentConfig = (await import(path)).default
+ }
+
+ return Reflect.get(currentConfig, p, receiver)
+ },
+ set(_, p, newValue, receiver) {
+ return Reflect.set(currentConfig, p, newValue, receiver)
+ },
+ },
+) as typeof _firstConfig & { invalidate(): void }
+
+export const __getConfig = () => currentConfig
diff --git a/bots/discord/src/constants.ts b/bots/discord/src/constants.ts
new file mode 100644
index 0000000..8e25126
--- /dev/null
+++ b/bots/discord/src/constants.ts
@@ -0,0 +1,9 @@
+export const MessageScanLabeledResponseReactions = {
+ train: '👍',
+ edit: '🔧',
+ delete: '❌',
+} as const
+
+export const DefaultEmbedColor = '#4E98F0'
+export const ReVancedLogoURL =
+ 'https://media.discordapp.net/attachments/1095487869923119144/1115436493050224660/revanced-logo.png'
diff --git a/bots/discord/src/context.ts b/bots/discord/src/context.ts
new file mode 100644
index 0000000..c63468b
--- /dev/null
+++ b/bots/discord/src/context.ts
@@ -0,0 +1,111 @@
+import { Database } from 'bun:sqlite'
+import { existsSync, readFileSync, readdirSync } from 'fs'
+import { join } from 'path'
+import { Client as APIClient } from '@revanced/bot-api'
+import { createLogger } from '@revanced/bot-shared'
+import { Client as DiscordClient, type Message, Partials } from 'discord.js'
+import { drizzle } from 'drizzle-orm/bun-sqlite'
+
+import * as schemas from './database/schemas'
+
+import type { default as Command, CommandOptionsOptions, CommandType } from './classes/Command'
+
+import { __getConfig, config } from './config'
+export { config, __getConfig }
+
+export const logger = createLogger({
+ level: config.logLevel === 'none' ? Number.MAX_SAFE_INTEGER : config.logLevel,
+})
+
+// Export a few things before we initialize commands
+import * as commands from './commands'
+
+export const api = {
+ client: new APIClient({
+ api: {
+ websocket: {
+ url: config.api.url,
+ },
+ },
+ }),
+ intentionallyDisconnecting: false,
+ disconnectCount: 0,
+}
+
+const DatabasePath = process.env['DATABASE_PATH']
+const DatabaseSchemaDir = join(import.meta.dir, '..', '.drizzle')
+
+let dbSchemaFileName: string | undefined
+
+if (DatabasePath && !existsSync(DatabasePath)) {
+ logger.warn('Database file not found, trying to create from schema...')
+
+ try {
+ const file = readdirSync(DatabaseSchemaDir, { withFileTypes: true })
+ .filter(file => file.isFile() && file.name.endsWith('.sql'))
+ .sort()
+ .at(-1)
+
+ if (!file) throw new Error('No schema file found')
+
+ dbSchemaFileName = file.name
+ logger.debug(`Using schema file: ${dbSchemaFileName}`)
+ } catch (e) {
+ logger.fatal('Could not create database from schema, check if the schema file exists and is accessible')
+ logger.fatal(e)
+ process.exit(1)
+ }
+}
+
+const db = new Database(DatabasePath, { readwrite: true, create: true })
+if (dbSchemaFileName) db.run(readFileSync(join(DatabaseSchemaDir, dbSchemaFileName)).toString())
+
+export const database = drizzle(db, {
+ schema: schemas,
+})
+
+export const discord = {
+ client: new DiscordClient({
+ intents: [
+ 'Guilds',
+ 'GuildMembers',
+ 'GuildModeration',
+ 'GuildMessages',
+ 'GuildMessageReactions',
+ 'DirectMessages',
+ 'DirectMessageReactions',
+ 'MessageContent',
+ ],
+ allowedMentions: {
+ parse: ['users'],
+ repliedUser: true,
+ },
+ partials: [Partials.Message, Partials.Reaction, Partials.GuildMember],
+ }),
+ commands: Object.fromEntries(Object.values(commands).map(cmd => [cmd.name, cmd])) as Record<
+ string,
+ Command
+ >,
+ stickyMessages: {} as Record<
+ string,
+ Record<
+ string,
+ {
+ /**
+ * Chat is active, so force send timer is also active
+ */
+ forceTimerActive: boolean
+ /**
+ * There was a message sent, so the timer is active
+ */
+ timerActive: boolean
+ timerMs: number
+ forceTimerMs?: number
+ send: (forced?: boolean) => Promise
+ currentMessage?: Message
+ timer?: NodeJS.Timeout
+ forceTimer?: NodeJS.Timeout
+ }
+ >
+ >,
+} as const
diff --git a/bots/discord/src/database/schemas.ts b/bots/discord/src/database/schemas.ts
new file mode 100644
index 0000000..0acee06
--- /dev/null
+++ b/bots/discord/src/database/schemas.ts
@@ -0,0 +1,29 @@
+import type { InferSelectModel } from 'drizzle-orm'
+import { integer, sqliteTable, text, uniqueIndex } from 'drizzle-orm/sqlite-core'
+
+export const responses = sqliteTable('responses', {
+ replyId: text('reply').primaryKey().notNull(),
+ channelId: text('channel').notNull(),
+ guildId: text('guild').notNull(),
+ referenceId: text('ref').notNull(),
+ label: text('label').notNull(),
+ content: text('text').notNull(),
+ correctedById: text('by'),
+})
+
+export const appliedPresets = sqliteTable(
+ 'applied_presets',
+ {
+ memberId: text('member').notNull(),
+ guildId: text('guild').notNull(),
+ removedRoles: text('roles', { mode: 'json' }).notNull().$type().default([]),
+ preset: text('preset').notNull(),
+ until: integer('until'),
+ },
+ table => ({
+ uniqueComposite: uniqueIndex('unique_composite').on(table.memberId, table.preset, table.guildId),
+ }),
+)
+
+export type Response = InferSelectModel
+export type AppliedPreset = InferSelectModel
diff --git a/bots/discord/src/events/api/disconnect.ts b/bots/discord/src/events/api/disconnect.ts
new file mode 100644
index 0000000..178980d
--- /dev/null
+++ b/bots/discord/src/events/api/disconnect.ts
@@ -0,0 +1,29 @@
+import { on, withContext } from '$utils/api/events'
+import { DisconnectReason, HumanizedDisconnectReason } from '@revanced/bot-shared'
+
+withContext(on, 'disconnect', ({ api, config, logger }, reason, msg) => {
+ if (reason === DisconnectReason.PlannedDisconnect && api.intentionallyDisconnecting) return
+
+ const ws = api.client.ws
+ if (!ws.disconnected) ws.disconnect()
+
+ logger.fatal(
+ `Disconnected from the bot API ${
+ reason in HumanizedDisconnectReason
+ ? `because ${HumanizedDisconnectReason[reason as keyof typeof HumanizedDisconnectReason]}`
+ : 'for an unknown reason'
+ }`,
+ )
+
+ if (api.disconnectCount >= (config.api.disconnectLimit ?? 3)) {
+ logger.fatal('Disconnected from bot API too many times')
+ // We don't want the process hanging
+ process.exit(1)
+ }
+
+ logger.info(
+ `Disconnected from bot API ${++api.disconnectCount} times (this time because: ${reason}, ${msg}), reconnecting again...`,
+ )
+
+ setTimeout(() => api.client.connect(), config.api.disconnectRetryInterval)
+})
diff --git a/bots/discord/src/events/api/ready.ts b/bots/discord/src/events/api/ready.ts
new file mode 100644
index 0000000..99fafac
--- /dev/null
+++ b/bots/discord/src/events/api/ready.ts
@@ -0,0 +1,7 @@
+import { on, withContext } from '$utils/api/events'
+
+withContext(on, 'ready', ({ api, logger }) => {
+ // Reset disconnect count, so it doesn't meet the threshold for an accidental disconnect
+ api.disconnectCount = 0
+ logger.info('Connected to the bot API')
+})
diff --git a/bots/discord/src/events/discord/cure.ts b/bots/discord/src/events/discord/cure.ts
new file mode 100644
index 0000000..a916558
--- /dev/null
+++ b/bots/discord/src/events/discord/cure.ts
@@ -0,0 +1,17 @@
+import { on } from '$/utils/discord/events'
+import { cureNickname } from '$/utils/discord/moderation'
+
+on('guildMemberUpdate', (_, newMember) => {
+ if (newMember.user.bot) return
+ cureNickname(newMember)
+})
+
+on('guildMemberAdd', member => {
+ if (member.user.bot) return
+ cureNickname(member)
+})
+
+on('messageCreate', msg => {
+ if (msg.author.bot || !msg.member) return
+ cureNickname(msg.member)
+})
diff --git a/bots/discord/src/events/discord/guildMemberAdd/applyRolePresets.ts b/bots/discord/src/events/discord/guildMemberAdd/applyRolePresets.ts
new file mode 100644
index 0000000..686350d
--- /dev/null
+++ b/bots/discord/src/events/discord/guildMemberAdd/applyRolePresets.ts
@@ -0,0 +1,16 @@
+import { appliedPresets } from '$/database/schemas'
+import { on, withContext } from '$/utils/discord/events'
+import { applyRolesUsingPreset } from '$/utils/discord/rolePresets'
+import { and, eq, gt } from 'drizzle-orm'
+
+withContext(on, 'guildMemberAdd', async ({ database }, member) => {
+ const applieds = await database.query.appliedPresets.findMany({
+ where: and(
+ eq(appliedPresets.memberId, member.id),
+ eq(appliedPresets.guildId, member.guild.id),
+ gt(appliedPresets.until, Date.now() / 1000),
+ ),
+ })
+
+ for (const { preset } of applieds) await applyRolesUsingPreset(preset, member)
+})
diff --git a/bots/discord/src/events/discord/interactionCreate/chatCommand.ts b/bots/discord/src/events/discord/interactionCreate/chatCommand.ts
new file mode 100644
index 0000000..3ae139e
--- /dev/null
+++ b/bots/discord/src/events/discord/interactionCreate/chatCommand.ts
@@ -0,0 +1,30 @@
+import CommandError from '$/classes/CommandError'
+import { createStackTraceEmbed } from '$utils/discord/embeds'
+import { on, withContext } from '$utils/discord/events'
+
+withContext(on, 'interactionCreate', async (context, interaction) => {
+ if (!interaction.isChatInputCommand()) return
+
+ const { logger, discord } = context
+ const command = discord.commands[interaction.commandName]
+
+ logger.debug(`Command ${interaction.commandName} being invoked by ${interaction.user.tag} via chat`)
+ if (!command) return void logger.error(`Chat command ${interaction.commandName} not implemented but registered!!!`)
+
+ try {
+ logger.debug(`Command ${interaction.commandName} being executed via chat`)
+ await command.onInteraction(context, interaction)
+ } catch (err) {
+ if (!(err instanceof CommandError))
+ logger.error(`Error while executing command ${interaction.commandName}:`, err)
+
+ await interaction[interaction.replied ? 'followUp' : 'reply']({
+ embeds: [err instanceof CommandError ? err.toEmbed() : createStackTraceEmbed(err)],
+ ephemeral: true,
+ })
+
+ // 100 and up are user errors
+ if (err instanceof CommandError && err.type < 100)
+ logger.error(`Command ${interaction.commandName} internally failed with error:`, err)
+ }
+})
diff --git a/bots/discord/src/events/discord/interactionCreate/contextMenuCommand.ts b/bots/discord/src/events/discord/interactionCreate/contextMenuCommand.ts
new file mode 100644
index 0000000..e98aa56
--- /dev/null
+++ b/bots/discord/src/events/discord/interactionCreate/contextMenuCommand.ts
@@ -0,0 +1,26 @@
+import CommandError from '$/classes/CommandError'
+import { createStackTraceEmbed } from '$utils/discord/embeds'
+import { on, withContext } from '$utils/discord/events'
+
+withContext(on, 'interactionCreate', async (context, interaction) => {
+ if (!interaction.isContextMenuCommand()) return
+
+ const { logger, discord } = context
+ const command = discord.commands[interaction.commandName]
+
+ logger.debug(`Command ${interaction.commandName} being invoked by ${interaction.user.tag} via context menu`)
+ if (!command)
+ return void logger.error(`Context menu command ${interaction.commandName} not implemented but registered!!!`)
+
+ try {
+ logger.debug(`Command ${interaction.commandName} being executed via context menu`)
+ await command.onContextMenuInteraction(context, interaction)
+ } catch (err) {
+ if (!(err instanceof CommandError))
+ logger.error(`Error while executing command ${interaction.commandName}:`, err)
+ await interaction[interaction.replied ? 'followUp' : 'reply']({
+ embeds: [err instanceof CommandError ? err.toEmbed() : createStackTraceEmbed(err)],
+ ephemeral: true,
+ })
+ }
+})
diff --git a/bots/discord/src/events/discord/interactionCreate/correctResponse.ts b/bots/discord/src/events/discord/interactionCreate/correctResponse.ts
new file mode 100644
index 0000000..5792a23
--- /dev/null
+++ b/bots/discord/src/events/discord/interactionCreate/correctResponse.ts
@@ -0,0 +1,113 @@
+import { responses } from '$/database/schemas'
+import { handleUserResponseCorrection } from '$/utils/discord/messageScan'
+import { createErrorEmbed, createStackTraceEmbed, createSuccessEmbed } from '$utils/discord/embeds'
+import { on, withContext } from '$utils/discord/events'
+
+import type { ButtonInteraction, StringSelectMenuInteraction, TextBasedChannel } from 'discord.js'
+import { eq } from 'drizzle-orm'
+
+// No permission check required as it is already done when the user reacts to a bot response
+withContext(on, 'interactionCreate', async (context, interaction) => {
+ const {
+ logger,
+ database: db,
+ config: { messageScan: msConfig },
+ } = context
+
+ if (!msConfig?.humanCorrections) return
+ if (!interaction.isStringSelectMenu() && !interaction.isButton()) return
+ if (!interaction.customId.startsWith('cr_')) return
+
+ const [, msgId, action] = interaction.customId.split('_') as ['cr', string, 'select' | 'cancel' | 'delete']
+ if (!msgId || !action) return
+
+ const response = await db.query.responses.findFirst({ where: eq(responses.replyId, msgId) })
+ // If the message isn't saved in my DB (unrelated message)
+ if (!response)
+ return void (await interaction.reply({
+ content: "I don't recall having sent this response, so I cannot correct it.",
+ ephemeral: true,
+ }))
+
+ try {
+ // We're gonna pretend reactionChannel is a text-based channel, but it can be many more
+ // But `messages` should always exist as a property
+ const guild = await interaction.client.guilds.fetch(response.guildId)
+ const channel = (await guild.channels.fetch(response.channelId)) as TextBasedChannel | null
+ const msg = await channel?.messages.fetch(msgId)
+
+ if (!msg) {
+ await interaction.deferUpdate()
+ await interaction.message.edit({
+ content: null,
+ embeds: [
+ createErrorEmbed(
+ 'Response not found',
+ 'Thank you for your feedback! Unfortunately, the response message could not be found (most likely deleted).',
+ ),
+ ],
+ components: [],
+ })
+
+ return
+ }
+
+ const editMessage = (content: string, description?: string) =>
+ editInteractionMessage(interaction, msg.url, content, description)
+ const handleCorrection = (label: string) =>
+ handleUserResponseCorrection(context, response, msg, label, interaction.user)
+
+ if (response.correctedById)
+ return await editMessage(
+ 'Response already corrected',
+ 'Thank you for your feedback! Unfortunately, this response has already been corrected by someone else.',
+ )
+
+ // We immediately know that the action is `select`
+ if (interaction.isStringSelectMenu()) {
+ const selectedLabel = interaction.values[0]!
+
+ await handleCorrection(selectedLabel)
+ await editMessage(
+ 'Message being trained',
+ `Thank you for your feedback! I've edited the response according to the selected label (\`${selectedLabel}\`). The message is now being trained. 🎉`,
+ )
+ } else {
+ switch (action) {
+ case 'cancel':
+ await editMessage('Canceled', 'You canceled this interaction. 😞')
+ break
+ case 'delete':
+ await handleCorrection(msConfig.humanCorrections.falsePositiveLabel)
+ await editMessage(
+ 'Marked as false positive',
+ 'The response has been deleted and marked as a false positive. Thank you for your feedback. 🎉',
+ )
+
+ break
+ }
+ }
+ } catch (e) {
+ logger.error('Failed to handle correct response interaction:', e)
+ await interaction.reply({
+ embeds: [createStackTraceEmbed(e)],
+ ephemeral: true,
+ })
+ }
+})
+
+const editInteractionMessage = async (
+ interaction: StringSelectMenuInteraction | ButtonInteraction,
+ replyUrl: string,
+ title: string,
+ description?: string,
+) => {
+ if (!interaction.deferred) await interaction.deferUpdate()
+ await interaction.message.edit({
+ content: null,
+ embeds: [
+ createSuccessEmbed(title, `${description ?? ''}\n\n**⬅️ Back to bot response**: ${replyUrl}`.trimStart()),
+ ],
+ components: [],
+ })
+}
diff --git a/bots/discord/src/events/discord/interactionCreate/trainMessage.ts b/bots/discord/src/events/discord/interactionCreate/trainMessage.ts
new file mode 100644
index 0000000..917ba10
--- /dev/null
+++ b/bots/discord/src/events/discord/interactionCreate/trainMessage.ts
@@ -0,0 +1,52 @@
+import { createErrorEmbed, createStackTraceEmbed, createSuccessEmbed } from '$utils/discord/embeds'
+import { on, withContext } from '$utils/discord/events'
+
+import type { TextBasedChannel } from 'discord.js'
+
+withContext(on, 'interactionCreate', async (context, interaction) => {
+ const {
+ logger,
+ config: { messageScan: msConfig },
+ } = context
+
+ if (!msConfig?.humanCorrections) return
+ if (!interaction.isStringSelectMenu()) return
+ if (!interaction.customId.startsWith('tr_')) return
+
+ const [, channelId, msgId] = interaction.customId.split('_') as ['tr', string, string]
+ if (!channelId || !msgId) return
+
+ try {
+ const channel = (await interaction.client.channels.fetch(channelId)) as TextBasedChannel | null
+ const msg = await channel?.messages.fetch(msgId)
+
+ if (!msg)
+ return void (await interaction.reply({
+ embeds: [
+ createErrorEmbed(
+ 'Message not found',
+ 'Thank you for your contribution! Unfortunately, the message could not be found.',
+ ),
+ ],
+ ephemeral: true,
+ }))
+
+ const selectedLabel = interaction.values[0]!
+ await context.api.client.trainMessage(msg.content, selectedLabel)
+ await interaction.reply({
+ embeds: [
+ createSuccessEmbed(
+ 'Message being trained',
+ `Thank you for your contribution! The selected message is being trained as \`${selectedLabel}\`. 🎉`,
+ ),
+ ],
+ ephemeral: true,
+ })
+ } catch (e) {
+ logger.error('Failed to handle train message interaction:', e)
+ await interaction.reply({
+ embeds: [createStackTraceEmbed(e)],
+ ephemeral: true,
+ })
+ }
+})
diff --git a/bots/discord/src/events/discord/messageCreate/messageCommand.ts b/bots/discord/src/events/discord/messageCreate/messageCommand.ts
new file mode 100644
index 0000000..328522e
--- /dev/null
+++ b/bots/discord/src/events/discord/messageCreate/messageCommand.ts
@@ -0,0 +1,64 @@
+import { type CommandArguments, CommandSpecialArgumentType } from '$/classes/Command'
+import CommandError from '$/classes/CommandError'
+import { createStackTraceEmbed } from '$utils/discord/embeds'
+import { on, withContext } from '$utils/discord/events'
+
+withContext(on, 'messageCreate', async (context, msg) => {
+ const { logger, discord, config } = context
+
+ if (msg.author.bot) return
+
+ const regex = new RegExp(
+ `^(?:${config.prefix ? `${escapeRegexSpecials(config.prefix)}|` : ''}${msg.client.user.toString()}\\s*)([a-zA-Z-_]+)(?:\\s+)?(.+)?`,
+ )
+ const matches = msg.content.match(regex)
+
+ if (!matches) return
+ const [, commandName, argsString] = matches
+ if (!commandName) return
+
+ const command = discord.commands[commandName]
+ logger.debug(`Command ${commandName} being invoked by ${msg.author.id} via message`)
+ if (!command) return void logger.debug(`Message command ${commandName} not implemented`)
+
+ const argsRegex: RegExp = /[^\s"]+|"([^"]*)"/g
+ const args: CommandArguments = []
+ let match: RegExpExecArray | null
+
+ // biome-ignore lint/suspicious/noAssignInExpressions: nuh uh
+ while ((match = argsRegex.exec(argsString ?? '')) !== null) {
+ const arg = match[1] ? match[1] : match[0]
+ const mentionMatch = arg.match(/<(@(?:!|&)?|#)(.+?)>/)
+
+ if (mentionMatch) {
+ const [, prefix, id] = mentionMatch
+
+ if (!id || !prefix) {
+ args.push('')
+ continue
+ }
+
+ args.push({
+ type: CommandSpecialArgumentType[prefix[1] === '&' ? 'Role' : prefix[0] === '#' ? 'Channel' : 'User'],
+ id,
+ })
+ } else args.push(arg)
+ }
+
+ try {
+ logger.debug(`Command ${commandName} being executed via message`)
+ await command.onMessage(context, msg, args)
+ } catch (err) {
+ if (!(err instanceof CommandError)) logger.error(`Error while executing command ${commandName}:`, err)
+ await msg.reply({ embeds: [err instanceof CommandError ? err.toEmbed() : createStackTraceEmbed(err)] })
+ }
+})
+
+const escapeRegexSpecials = (str: string): string => {
+ let escapedStr = ''
+ for (const char of str) {
+ if (['.', '+', '*', '?', '$', '(', ')', '[', ']', '{', '}', '|', '\\'].includes(char)) escapedStr += `\\${char}`
+ else escapedStr += char
+ }
+ return escapedStr
+}
diff --git a/bots/discord/src/events/discord/messageCreate/messageScan.ts b/bots/discord/src/events/discord/messageCreate/messageScan.ts
new file mode 100644
index 0000000..e60d864
--- /dev/null
+++ b/bots/discord/src/events/discord/messageCreate/messageScan.ts
@@ -0,0 +1,105 @@
+import { responses } from '$/database/schemas'
+import { getResponseFromText, messageMatchesFilter } from '$/utils/discord/messageScan'
+import { createMessageScanResponseEmbed } from '$utils/discord/embeds'
+import { on, withContext } from '$utils/discord/events'
+
+withContext(on, 'messageCreate', async (context, msg) => {
+ const {
+ api,
+ config: { messageScan: config },
+ database: db,
+ logger,
+ } = context
+
+ if (!config || !config.responses) return
+ if (msg.author.bot && !config.scanBots) return
+ if (!msg.inGuild() && !config.scanOutsideGuilds) return
+ if (msg.inGuild() && msg.member?.partial) await msg.member.fetch()
+
+ const filteredResponses = config.responses.filter(x => messageMatchesFilter(msg, x.filterOverride ?? config.filter))
+ if (!filteredResponses.length) return
+
+ if (msg.content.length) {
+ try {
+ logger.debug(`Classifying message ${msg.id}, possible responses is ${filteredResponses.length}`)
+
+ const { response, label, respondToReply } = await getResponseFromText(
+ msg.content,
+ filteredResponses,
+ context,
+ )
+
+ if (response) {
+ logger.debug('Response found')
+
+ const toReply = respondToReply ? (msg.reference?.messageId ? await msg.fetchReference() : msg) : msg
+ const reply = await toReply.reply({
+ ...response,
+ embeds: response.embeds?.map(createMessageScanResponseEmbed),
+ })
+
+ if (label) {
+ await db.insert(responses).values({
+ replyId: reply.id,
+ channelId: reply.channel.id,
+ guildId: reply.guild!.id,
+ referenceId: msg.id,
+ label,
+ content: msg.content,
+ })
+ }
+ }
+ } catch (e) {
+ logger.error('Failed to classify message:', e)
+ }
+ }
+
+ if (msg.attachments.size && config.attachments?.scanAttachments) {
+ logger.debug(`Classifying message attachments for ${msg.id}, possible responses is ${filteredResponses.length}`)
+
+ for (const attachment of msg.attachments.values()) {
+ const mimeType = attachment.contentType?.split(';')?.[0]
+ if (!mimeType) return void logger.warn(`No MIME type for attachment: ${attachment.url}`)
+
+ if (config.attachments.allowedMimeTypes && !config.attachments.allowedMimeTypes.includes(mimeType)) {
+ logger.debug(`Disallowed MIME type for attachment: ${attachment.url}, ${mimeType}`)
+ continue
+ }
+
+ const isTextFile = mimeType.startsWith('text/')
+
+ if (isTextFile && attachment.size > (config.attachments.maxTextFileSize ?? 512 * 1000)) {
+ logger.debug(`Attachment ${attachment.url} is too large be to scanned, size is ${attachment.size}`)
+ continue
+ }
+
+ try {
+ let response: Awaited>['response'] | undefined
+
+ if (isTextFile) {
+ const content = await (await fetch(attachment.url)).text()
+ response = await getResponseFromText(content, filteredResponses, context, {
+ textRegexesOnly: true,
+ }).then(it => it.response)
+ } else {
+ const { text: content } = await api.client.parseImage(attachment.url)
+ response = await getResponseFromText(content, filteredResponses, context, {
+ imageTriggersOnly: true,
+ }).then(it => it.response)
+ }
+
+ if (response) {
+ logger.debug(`Response found for attachment: ${attachment.url}`)
+ await msg.reply({
+ ...response,
+ embeds: response.embeds?.map(createMessageScanResponseEmbed),
+ })
+
+ break
+ }
+ } catch (e) {
+ logger.error(`Failed to parse attachment: ${attachment.url}`, e)
+ }
+ }
+ }
+})
diff --git a/bots/discord/src/events/discord/messageCreate/stickyMessageReset.ts b/bots/discord/src/events/discord/messageCreate/stickyMessageReset.ts
new file mode 100644
index 0000000..8a7a4f5
--- /dev/null
+++ b/bots/discord/src/events/discord/messageCreate/stickyMessageReset.ts
@@ -0,0 +1,42 @@
+import { on, withContext } from '$utils/discord/events'
+
+withContext(on, 'messageCreate', async ({ discord, logger }, msg) => {
+ if (!msg.inGuild()) return
+ if (msg.author.id === msg.client.user.id) return
+
+ const store = discord.stickyMessages[msg.guildId]?.[msg.channelId]
+ if (!store) return
+
+ if (store.timerActive) {
+ // Timer is already active, so we try to start the force timer
+ if (store.forceTimerMs) {
+ // Force timer isn't active, so we start it
+ if (!store.forceTimerActive) {
+ logger.debug(
+ `Channel ${msg.channelId} in guild ${msg.guildId} is active, starting force send timer and clearing existing timer`,
+ )
+
+ // Clear the timer
+ clearTimeout(store.timer)
+ store.timerActive = false
+
+ // (Re)start the force timer
+ store.forceTimerActive = true
+ if (!store.forceTimer)
+ store.forceTimer = setTimeout(
+ () =>
+ store.send(true).then(() => {
+ store.forceTimerActive = false
+ }),
+ store.forceTimerMs,
+ ) as NodeJS.Timeout
+ else store.forceTimer.refresh()
+ // Force timer is already active, so we force send
+ } else store.send()
+ }
+ } else if (!store.forceTimerActive) {
+ // Both timers aren't active, so we start the timer
+ store.timerActive = true
+ if (!store.timer) store.timer = setTimeout(store.send, store.timerMs) as NodeJS.Timeout
+ }
+})
diff --git a/bots/discord/src/events/discord/messageReactionAdd/correctResponse.ts b/bots/discord/src/events/discord/messageReactionAdd/correctResponse.ts
new file mode 100644
index 0000000..23a536a
--- /dev/null
+++ b/bots/discord/src/events/discord/messageReactionAdd/correctResponse.ts
@@ -0,0 +1,141 @@
+import { MessageScanLabeledResponseReactions as Reactions } from '$/constants'
+import { createErrorEmbed, createStackTraceEmbed, createSuccessEmbed } from '$/utils/discord/embeds'
+import { on, withContext } from '$/utils/discord/events'
+
+import {
+ ActionRowBuilder,
+ ButtonBuilder,
+ ButtonStyle,
+ StringSelectMenuBuilder,
+ StringSelectMenuOptionBuilder,
+} from 'discord.js'
+
+import type { ConfigMessageScanResponseLabelConfig } from '$/../config.schema'
+import { responses } from '$/database/schemas'
+import { handleUserResponseCorrection } from '$/utils/discord/messageScan'
+import { isAdmin } from '$/utils/discord/permissions'
+import { eq } from 'drizzle-orm'
+
+const PossibleReactions = Object.values(Reactions) as string[]
+
+withContext(on, 'messageReactionAdd', async (context, rct, user) => {
+ if (user.bot) return
+
+ const { database: db, logger, config } = context
+ const { messageScan: msConfig } = config
+
+ // If there's no config, we can't do anything
+ if (!msConfig?.humanCorrections) return
+
+ const reaction = await rct.fetch()
+ const reactionMessage = await reaction.message.fetch()
+
+ if (reactionMessage.author.id !== reaction.client.user!.id) return
+ if (!PossibleReactions.includes(reaction.emoji.name!)) return
+ await rct.users.remove(user.id)
+
+ if (!isAdmin(reactionMessage.member || reactionMessage.author)) {
+ // User is in guild, and config has member requirements
+ if (reactionMessage.inGuild() && msConfig.humanCorrections.allow) {
+ const {
+ allow: { users: allowedUsers, members: allowedMembers },
+ } = msConfig.humanCorrections
+
+ if (allowedMembers) {
+ const member = await reactionMessage.guild.members.fetch(user.id)
+ const { permissions, roles } = allowedMembers
+
+ if (
+ !(
+ (permissions ? member.permissions.has(permissions) : false) ||
+ roles?.some(role => member.roles.cache.has(role))
+ )
+ )
+ return
+ } else if (!allowedUsers?.includes(user.id)) return
+ } else
+ return void logger.warn(
+ 'No member or user requirements set for human corrections, all requests will be ignored',
+ )
+ }
+
+ // Sanity check
+ const response = await db.query.responses.findFirst({ where: eq(responses.replyId, rct.message.id) })
+ if (!response || response.correctedById) return
+
+ logger.debug(`User ${user.id} is trying to correct the response ${rct.message.id}`)
+
+ const handleCorrection = (label: string) =>
+ handleUserResponseCorrection(context, response, reactionMessage, label, user)
+
+ try {
+ if (reaction.emoji.name === Reactions.train) {
+ // Bot is right, nice!
+
+ await handleCorrection(response.label)
+ await user.send({ embeds: [createSuccessEmbed('Trained message', 'Thank you for your feedback.')] })
+ } else if (reaction.emoji.name === Reactions.edit) {
+ // Bot is wrong :(
+
+ const labels = msConfig.responses!.flatMap(r =>
+ r.triggers
+ .text!.filter((t): t is ConfigMessageScanResponseLabelConfig => 'label' in t)
+ .map(t => t.label),
+ )
+
+ const componentPrefix = `cr_${reactionMessage.id}`
+ const select = new StringSelectMenuBuilder().setCustomId(`${componentPrefix}_select`)
+
+ for (const label of labels) {
+ const opt = new StringSelectMenuOptionBuilder().setLabel(label).setValue(label)
+
+ if (label === response.label) {
+ opt.setDefault(true)
+ opt.setLabel(`${label} (current)`)
+ opt.setDescription('This is the current label of the message')
+ }
+
+ select.addOptions(opt)
+ }
+
+ const rows = [
+ new ActionRowBuilder().addComponents(select),
+ new ActionRowBuilder().addComponents(
+ new ButtonBuilder()
+ .setEmoji('⬅️')
+ .setLabel('Cancel')
+ .setStyle(ButtonStyle.Secondary)
+ .setCustomId(`${componentPrefix}_cancel`),
+ new ButtonBuilder()
+ .setEmoji(Reactions.delete)
+ .setLabel('Delete (mark as false positive)')
+ .setStyle(ButtonStyle.Danger)
+ .setCustomId(`${componentPrefix}_delete`),
+ ),
+ ]
+
+ await user.send({
+ content: 'Please pick the right label for the message (you can only do this once!)',
+ components: rows,
+ })
+ } else if (reaction.emoji.name === Reactions.delete) {
+ await handleCorrection(msConfig.humanCorrections.falsePositiveLabel)
+ await user.send({ content: 'The response has been deleted and marked as a false positive.' })
+ }
+ } catch (e) {
+ logger.error('Failed to correct response:', e)
+ user.send({
+ embeds: [createStackTraceEmbed(e)],
+ }).catch(() => {
+ reactionMessage.reply({
+ content: `<@${user.id}>`,
+ embeds: [
+ createErrorEmbed(
+ 'Enable your DMs!',
+ 'I cannot send you messages. Please enable your DMs to use this feature.',
+ ),
+ ],
+ })
+ })
+ }
+})
diff --git a/bots/discord/src/events/discord/ready.ts b/bots/discord/src/events/discord/ready.ts
new file mode 100644
index 0000000..6d54ab8
--- /dev/null
+++ b/bots/discord/src/events/discord/ready.ts
@@ -0,0 +1,107 @@
+import { database, logger } from '$/context'
+import { appliedPresets } from '$/database/schemas'
+import { applyCommonEmbedStyles } from '$/utils/discord/embeds'
+import { on, withContext } from '$/utils/discord/events'
+import { removeRolePreset } from '$/utils/discord/rolePresets'
+import { and, eq, lt } from 'drizzle-orm'
+
+import type { Client } from 'discord.js'
+
+export default withContext(on, 'ready', async ({ config, discord, logger }, client) => {
+ logger.info(`Connected to Discord API, logged in as ${client.user.displayName} (@${client.user.tag})!`)
+ logger.info(`Bot is in ${client.guilds.cache.size} guilds`)
+
+ if (config.stickyMessages)
+ for (const [guildId, channels] of Object.entries(config.stickyMessages)) {
+ const guild = await client.guilds.fetch(guildId)
+ // In case of configuration refresh, this will not be nullable
+ const oldStore = discord.stickyMessages[guildId]
+ discord.stickyMessages[guildId] = {}
+
+ for (const [channelId, { message, timeout, forceSendTimeout }] of Object.entries(channels)) {
+ const channel = await guild.channels.fetch(channelId)
+ if (!channel?.isTextBased())
+ return void logger.warn(
+ `Channel ${channelId} in guild ${guildId} is not a text channel, sticky messages will not be sent`,
+ )
+
+ const send = async (forced = false) => {
+ try {
+ const msg = await channel.send({
+ ...message,
+ embeds: message.embeds?.map(it => applyCommonEmbedStyles(it, true, true, true)),
+ })
+
+ const store = discord.stickyMessages[guildId]![channelId]
+ if (!store) return
+
+ await store.currentMessage?.delete().catch()
+ store.currentMessage = msg
+
+ // Clear any remaining timers
+ clearTimeout(store.timer)
+ clearTimeout(store.forceTimer)
+ store.forceTimerActive = store.timerActive = false
+
+ if (!forced)
+ logger.debug(
+ `Timeout ended for sticky message in channel ${channelId} in guild ${guildId}, channel is inactive`,
+ )
+ else
+ logger.debug(
+ `Forced send timeout for sticky message in channel ${channelId} in guild ${guildId} ended, channel is too active`,
+ )
+
+ logger.debug(`Sent sticky message to channel ${channelId} in guild ${guildId}`)
+ } catch (e) {
+ logger.error(
+ `Error while sending sticky message to channel ${channelId} in guild ${guildId}:`,
+ e,
+ )
+ }
+ }
+
+ // Set up the store
+ discord.stickyMessages[guildId]![channelId] = {
+ forceTimerActive: false,
+ timerActive: false,
+ forceTimerMs: forceSendTimeout,
+ timerMs: timeout,
+ send,
+ // If the store exists before the configuration refresh, take its current message
+ currentMessage: oldStore?.[channelId]?.currentMessage,
+ }
+
+ // Send a new sticky message immediately, as well as deleting the old/outdated message, if it exists
+ await send()
+ }
+ }
+
+ if (config.rolePresets) {
+ removeExpiredPresets(client)
+ setTimeout(() => removeExpiredPresets(client), config.rolePresets.checkExpiredEvery)
+ }
+})
+
+const removeExpiredPresets = async (client: Client) => {
+ logger.debug('Checking for expired role presets...')
+
+ const expireds = await database.query.appliedPresets.findMany({
+ where: lt(appliedPresets.until, Math.floor(Date.now() / 1000)),
+ })
+
+ for (const expired of expireds)
+ try {
+ logger.debug(`Removing role preset for ${expired.memberId} in ${expired.guildId}`)
+
+ const guild = await client.guilds.fetch(expired.guildId)
+ const member = await guild.members.fetch(expired.memberId)
+
+ await removeRolePreset(member, expired.preset)
+ await database
+ .delete(appliedPresets)
+ .where(and(eq(appliedPresets.guildId, expired.guildId), eq(appliedPresets.memberId, expired.memberId)))
+ } catch (e) {
+ logger.error(`Error while removing role preset for ${expired.memberId} in ${expired.guildId}: ${e}`)
+ }
+}
diff --git a/bots/discord/src/events/register.ts b/bots/discord/src/events/register.ts
new file mode 100644
index 0000000..fbab0e6
--- /dev/null
+++ b/bots/discord/src/events/register.ts
@@ -0,0 +1,2 @@
+import './discord'
+import './api'
diff --git a/bots/discord/src/index.ts b/bots/discord/src/index.ts
new file mode 100644
index 0000000..2aaf35c
--- /dev/null
+++ b/bots/discord/src/index.ts
@@ -0,0 +1,19 @@
+import { api, discord, logger } from '$/context'
+import { getMissingEnvironmentVariables } from '@revanced/bot-shared'
+
+import './events/register'
+
+// Check if token exists
+const missingEnvs = getMissingEnvironmentVariables(['DISCORD_TOKEN', 'DATABASE_PATH'])
+if (missingEnvs.length) {
+ for (const env of missingEnvs) logger.fatal(`${env} is not defined in environment variables`)
+ process.exit(1)
+}
+
+// Handle uncaught exceptions
+
+process.on('uncaughtException', error => console.error('Uncaught exception:', error))
+process.on('unhandledRejection', reason => console.error('Unhandled rejection:', reason))
+
+api.client.connect()
+discord.client.login()
diff --git a/bots/discord/src/utils/api/events.ts b/bots/discord/src/utils/api/events.ts
new file mode 100644
index 0000000..363eda3
--- /dev/null
+++ b/bots/discord/src/utils/api/events.ts
@@ -0,0 +1,20 @@
+import type { ClientWebSocketEvents } from '@revanced/bot-api'
+import * as context from '../../context'
+
+const { client } = context.api
+
+export const withContext = (
+ fn: typeof on | typeof once,
+ event: Event,
+ listener: ListenerWithContextOf,
+ // @ts-expect-error: Not smart enough, sorry!
+) => fn(event, (...args) => listener(context, ...args))
+
+export const on = (event: Event, listener: ListenerOf) => client.on(event, listener)
+export const once = (event: Event, listener: ListenerOf) => client.once(event, listener)
+
+export type EventName = keyof ClientWebSocketEvents
+export type ListenerOf = ClientWebSocketEvents[Event]
+export type ListenerWithContextOf = (
+ ...args: [typeof import('../../context'), ...Parameters]
+) => void | Promise
diff --git a/bots/discord/src/utils/discord/embeds.ts b/bots/discord/src/utils/discord/embeds.ts
new file mode 100644
index 0000000..453a3a8
--- /dev/null
+++ b/bots/discord/src/utils/discord/embeds.ts
@@ -0,0 +1,83 @@
+import { DefaultEmbedColor, ReVancedLogoURL } from '$/constants'
+import { type APIEmbed, EmbedBuilder, type EmbedField, type JSONEncodable, type User } from 'discord.js'
+import type { ConfigMessageScanResponseMessage } from '../../../config.schema'
+
+export const createErrorEmbed = (title: string | null, description?: string) =>
+ applyCommonEmbedStyles(
+ new EmbedBuilder()
+ .setTitle(title)
+ .setDescription(description ?? null)
+ .setAuthor({ name: 'Error' })
+ .setColor('Red'),
+ )
+
+export const createStackTraceEmbed = (stack: unknown) =>
+ // biome-ignore lint/style/useTemplate: shut
+ createErrorEmbed('An exception was thrown', '```js\n' + stack + '```')
+
+export const createSuccessEmbed = (title: string | null, description?: string) =>
+ applyCommonEmbedStyles(
+ new EmbedBuilder()
+ .setTitle(title)
+ .setDescription(description ?? null)
+ .setColor('Green'),
+ )
+
+export const createMessageScanResponseEmbed = (
+ response: NonNullable[number],
+) => applyCommonEmbedStyles(response, true, true, true)
+
+export const createModerationActionEmbed = (
+ action: string,
+ user: User,
+ moderator: User,
+ reason?: string,
+ expires?: number | null,
+ extraFields?: EmbedField[][],
+) => {
+ const fields: EmbedField[] = []
+ if (extraFields?.[0]) fields.push(...extraFields[0])
+ if (reason) fields.push({ name: 'Reason', value: reason, inline: true })
+ if (Number.isInteger(expires) || expires === null)
+ fields.push({
+ name: 'Expires',
+ value: Number.isInteger(expires) ? `` : 'Never',
+ inline: true,
+ })
+ if (extraFields?.[1]) fields.push(...extraFields[1])
+
+ const embed = new EmbedBuilder()
+ .setTitle(`${action} ${user.tag}`)
+ .setDescription(`${user.toString()} was ${action.toLowerCase()} by ${moderator.toString()}`)
+ .addFields(fields)
+ .setThumbnail(user.displayAvatarURL({ forceStatic: true }))
+
+ return applyCommonEmbedStyles(embed, true, true, true)
+}
+
+export const applyReferenceToModerationActionEmbed = (embed: EmbedBuilder, reference: string) => {
+ embed.addFields({ name: 'Reference', value: `[Jump to message](${reference})`, inline: true })
+ return embed
+}
+
+export const applyCommonEmbedStyles = (
+ embed: EmbedBuilder | JSONEncodable | APIEmbed,
+ setThumbnail = false,
+ setFooter = false,
+ setColor = false,
+) => {
+ // biome-ignore lint/style/noParameterAssign: While this is confusing, it is fine for this purpose
+ if ('toJSON' in embed) embed = embed.toJSON()
+ const builder = new EmbedBuilder(embed)
+
+ if (setFooter)
+ builder.setFooter({
+ text: 'ReVanced',
+ iconURL: ReVancedLogoURL,
+ })
+
+ if (setColor) builder.setColor(DefaultEmbedColor)
+ if (setThumbnail) builder.setThumbnail(ReVancedLogoURL)
+
+ return builder
+}
diff --git a/bots/discord/src/utils/discord/events.ts b/bots/discord/src/utils/discord/events.ts
new file mode 100644
index 0000000..0283471
--- /dev/null
+++ b/bots/discord/src/utils/discord/events.ts
@@ -0,0 +1,23 @@
+import * as context from '$/context'
+import type { ClientEvents } from 'discord.js'
+
+const { client } = context.discord
+
+export const withContext = (
+ fn: typeof on | typeof once,
+ event: Event,
+ listener: ListenerWithContextOf,
+) => fn(event, (...args) => listener(context, ...args))
+
+export const on = (event: Event, listener: ListenerOf) => client.on(event, listener)
+export const once = (event: Event, listener: ListenerOf) => client.once(event, listener)
+
+export type EventName = keyof ClientEvents
+export type EventMap = {
+ [K in EventName]: ListenerOf
+}
+
+type ListenerOf = (...args: ClientEvents[Event]) => void | Promise
+type ListenerWithContextOf = (
+ ...args: [typeof import('$/context'), ...ClientEvents[Event]]
+) => void | Promise
diff --git a/bots/discord/src/utils/discord/messageScan.ts b/bots/discord/src/utils/discord/messageScan.ts
new file mode 100644
index 0000000..43026b7
--- /dev/null
+++ b/bots/discord/src/utils/discord/messageScan.ts
@@ -0,0 +1,201 @@
+import { type Response, responses } from '$/database/schemas'
+import type { Config, ConfigMessageScanResponse, ConfigMessageScanResponseLabelConfig } from 'config.schema'
+import { ButtonStyle, ComponentType } from 'discord.js'
+import type { APIActionRowComponent, APIButtonComponent, Message, PartialUser, User } from 'discord.js'
+import { eq } from 'drizzle-orm'
+import { createMessageScanResponseEmbed } from './embeds'
+
+export const getResponseFromText = async (
+ content: string,
+ responses: ConfigMessageScanResponse[],
+ // Just to be safe that we will never use data from the context parameter
+ { api, logger }: Omit,
+ flags: { imageTriggersOnly?: boolean; textRegexesOnly?: boolean } = {},
+): Promise<
+ Omit & { label?: string; triggers?: ConfigMessageScanResponse['triggers'] }
+> => {
+ type ResponseConfig = Awaited>
+ let responseConfig: Omit & { triggers?: ResponseConfig['triggers'] } = {
+ triggers: undefined,
+ response: null,
+ }
+
+ const firstLabelIndexes: number[] = []
+
+ // Test if all regexes before a label trigger is matched
+ for (let i = 0; i < responses.length; i++) {
+ const trigger = responses[i]!
+
+ // Filter override check is not neccessary here, we are already passing responses that match the filter
+ // from the messageCreate handler, see line 17 of messageCreate handler
+ const {
+ triggers: { text: textTriggers, image: imageTriggers },
+ } = trigger
+
+ if (flags.imageTriggersOnly) {
+ if (imageTriggers)
+ for (const regex of imageTriggers)
+ if (regex.test(content)) {
+ logger.debug(`Message matched regex (OCR mode): ${regex.source}`)
+ responseConfig = trigger
+ break
+ }
+ } else {
+ for (let j = 0; j < textTriggers!.length; j++) {
+ const regex = textTriggers![j]!
+
+ if (regex instanceof RegExp) {
+ if (regex.test(content)) {
+ logger.debug(`Message matched regex (before mode): ${regex.source}`)
+ responseConfig = trigger
+ break
+ }
+ } else {
+ firstLabelIndexes[i] = j
+ break
+ }
+ }
+ }
+ }
+
+ // If none of the regexes match, we can search for labels immediately
+ if (!responseConfig.triggers && !flags.textRegexesOnly) {
+ logger.debug('No match from before regexes, doing NLP')
+ const scan = await api.client.parseText(content)
+ if (scan.labels.length) {
+ const matchedLabel = scan.labels[0]!
+ logger.debug(`Message matched label with confidence: ${matchedLabel.name}, ${matchedLabel.confidence}`)
+
+ let trigger: ConfigMessageScanResponseLabelConfig | undefined
+ const response = responses.find(x => {
+ const config = x.triggers.text!.find(
+ (x): x is ConfigMessageScanResponseLabelConfig => 'label' in x && x.label === matchedLabel.name,
+ )
+ if (config) trigger = config
+ return config
+ })
+
+ if (!response) {
+ logger.warn(`No response config found for label ${matchedLabel.name}`)
+ // This returns the default value set in line 17, which means no response matched
+ return responseConfig
+ }
+
+ if (matchedLabel.confidence >= trigger!.threshold) {
+ logger.debug('Label confidence is enough')
+ responseConfig = { ...responseConfig, ...response, label: trigger!.label }
+ }
+ }
+ }
+
+ // If we still don't have a response config, we can match all regexes after the initial label trigger
+ if (!responseConfig.triggers && !flags.imageTriggersOnly) {
+ logger.debug('No match from NLP, doing after regexes')
+ for (let i = 0; i < responses.length; i++) {
+ const {
+ triggers: { text: textTriggers },
+ } = responses[i]!
+ const firstLabelIndex = firstLabelIndexes[i] ?? -1
+
+ for (let j = firstLabelIndex + 1; j < textTriggers!.length; j++) {
+ const trigger = textTriggers![j]!
+
+ if (trigger instanceof RegExp) {
+ if (trigger.test(content)) {
+ logger.debug(`Message matched regex (after mode): ${trigger.source}`)
+ responseConfig = responses[i]!
+ break
+ }
+ }
+ }
+ }
+ }
+
+ return responseConfig
+}
+
+export const messageMatchesFilter = (message: Message, filter: NonNullable['filter']) => {
+ if (!filter) return true
+
+ const memberRoles = new Set(message.member?.roles.cache.keys())
+ const { blacklist, whitelist } = filter
+
+ // If matches only blacklist, will return false
+ // If matches whitelist but also matches blacklist, will return false
+ // If matches only whitelist, will return true
+ // If matches neither, will return true
+ return (
+ (whitelist
+ ? whitelist.channels?.includes(message.channelId) ||
+ whitelist.roles?.some(role => memberRoles.has(role)) ||
+ whitelist.users?.includes(message.author.id)
+ : true) &&
+ !(
+ blacklist &&
+ (blacklist.channels?.includes(message.channelId) ||
+ blacklist.roles?.some(role => memberRoles.has(role)) ||
+ blacklist.users?.includes(message.author.id))
+ )
+ )
+}
+
+export const handleUserResponseCorrection = async (
+ { api, database: db, config: { messageScan: msConfig }, logger }: typeof import('$/context'),
+ response: Response,
+ reply: Message,
+ label: string,
+ user: User | PartialUser,
+) => {
+ const correctLabelResponse = msConfig!.responses!.find(r =>
+ r.triggers.text!.some(t => 'label' in t && t.label === label),
+ )
+
+ if (!correctLabelResponse) throw new Error('Cannot find label config for the selected label')
+ if (!correctLabelResponse.response) return void (await reply.delete())
+
+ if (response.label !== label) {
+ db.update(responses)
+ .set({
+ label,
+ correctedById: user.id,
+ })
+ .where(eq(responses.replyId, response.replyId))
+
+ return void (await reply.edit({
+ ...correctLabelResponse.response,
+ embeds: correctLabelResponse.response.embeds?.map(createMessageScanResponseEmbed),
+ components: [],
+ }))
+ }
+
+ await api.client.trainMessage(response.content, label)
+ logger.debug(`User ${user.id} trained message ${response.replyId} as ${label} (positive)`)
+
+ await reply.edit({
+ components: [],
+ })
+}
+
+export const createMessageScanResponseComponents = (reply: Message) => [
+ {
+ type: ComponentType.ActionRow,
+ components: [
+ {
+ type: ComponentType.Button,
+ style: ButtonStyle.Secondary,
+ emoji: {
+ id: '👍',
+ },
+ custom_id: `train:${reply.id}`,
+ },
+ {
+ type: ComponentType.Button,
+ style: ButtonStyle.Secondary,
+ emoji: {
+ id: '🔧',
+ },
+ custom_id: `edit:${reply.id}`,
+ },
+ ],
+ } as APIActionRowComponent,
+]
diff --git a/bots/discord/src/utils/discord/moderation.ts b/bots/discord/src/utils/discord/moderation.ts
new file mode 100644
index 0000000..64704fa
--- /dev/null
+++ b/bots/discord/src/utils/discord/moderation.ts
@@ -0,0 +1,66 @@
+import { config, logger } from '$/context'
+import decancer from 'decancer'
+import type { CommandInteraction, EmbedBuilder, Guild, GuildMember, Message, User } from 'discord.js'
+import { applyReferenceToModerationActionEmbed, createModerationActionEmbed } from './embeds'
+
+const PresetLogAction = {
+ apply: 'Applied role preset to',
+ remove: 'Removed role preset from',
+} as const
+
+export const sendPresetReplyAndLogs = (
+ action: keyof typeof PresetLogAction,
+ interaction: CommandInteraction | Message,
+ executor: GuildMember,
+ user: User,
+ preset: string,
+ expires?: number | null,
+) =>
+ sendModerationReplyAndLogs(
+ interaction,
+ createModerationActionEmbed(PresetLogAction[action], user, executor.user, undefined, expires, [
+ [{ name: 'Preset', value: preset, inline: true }],
+ ]),
+ )
+
+export const sendModerationReplyAndLogs = async (interaction: CommandInteraction | Message, embed: EmbedBuilder) => {
+ const reply = await interaction.reply({ embeds: [embed] }).then(it => it.fetch())
+ const logChannel = await getLogChannel(interaction.guild!)
+ await logChannel?.send({ embeds: [applyReferenceToModerationActionEmbed(embed, reply.url)] })
+}
+
+export const getLogChannel = async (guild: Guild) => {
+ const logConfig = config.moderation?.log
+ if (!logConfig) return
+
+ try {
+ const channel = await guild.channels.fetch(logConfig.thread ?? logConfig.channel)
+ if (!channel?.isTextBased())
+ return void logger.warn('The moderation log channel does not exist, skipping logging')
+
+ return channel
+ } catch (error) {
+ logger.warn('Failed to fetch the moderation log channel:', error)
+ }
+
+ return
+}
+
+export const cureNickname = async (member: GuildMember) => {
+ if (!member.manageable) return
+ const name = member.displayName
+ let cured = decancer(name)
+ .toString()
+ .replace(new RegExp(config.moderation?.cure?.removeCharactersRegex ?? '[^a-zA-Z0-9 \\-_]', 'g'), '')
+
+ if (cured.length < (config?.moderation?.cure?.minimumNameLength ?? 3))
+ cured =
+ member.user.username.length >= 3
+ ? member.user.username
+ : (config.moderation?.cure?.defaultName ?? 'Server member')
+
+ if (cured.toLowerCase() === name.toLowerCase()) return
+
+ await member.setNickname(cured, 'Nickname cured')
+ logger.log(`Cured nickname for ${member.user.tag} (${member.id}) from "${name}"`)
+}
diff --git a/bots/discord/src/utils/discord/permissions.ts b/bots/discord/src/utils/discord/permissions.ts
new file mode 100644
index 0000000..4c6d6cd
--- /dev/null
+++ b/bots/discord/src/utils/discord/permissions.ts
@@ -0,0 +1,14 @@
+import { GuildMember, type User } from 'discord.js'
+import { config } from '../../context'
+
+export const isAdmin = (userOrMember: User | GuildMember) => {
+ return (
+ config.admin?.users?.includes(userOrMember.id) ||
+ (userOrMember instanceof GuildMember && isMemberAdmin(userOrMember))
+ )
+}
+
+export const isMemberAdmin = (member: GuildMember) => {
+ const roles = new Set(member.roles.cache.keys())
+ return Boolean(config?.admin?.roles?.[member.guild.id]?.some(role => roles.has(role)))
+}
diff --git a/bots/discord/src/utils/discord/rolePresets.ts b/bots/discord/src/utils/discord/rolePresets.ts
new file mode 100644
index 0000000..4b1ab79
--- /dev/null
+++ b/bots/discord/src/utils/discord/rolePresets.ts
@@ -0,0 +1,75 @@
+import { config, database } from '$/context'
+import { appliedPresets } from '$/database/schemas'
+import type { GuildMember } from 'discord.js'
+import { and, eq } from 'drizzle-orm'
+
+// TODO: Fix this type
+type PresetKey = string
+
+export const applyRolePreset = async (member: GuildMember, presetName: PresetKey, expires: number) => {
+ const { removed, callback } = await applyRolesUsingPreset(presetName, member)
+ const until = expires === Infinity ? null : Math.ceil(expires / 1000)
+
+ await database
+ .insert(appliedPresets)
+ .values({
+ memberId: member.id,
+ guildId: member.guild.id,
+ preset: presetName,
+ removedRoles: removed,
+ until,
+ })
+ .onConflictDoUpdate({
+ target: [appliedPresets.memberId, appliedPresets.preset, appliedPresets.guildId],
+ set: { until },
+ })
+ .then(callback)
+}
+
+export const removeRolePreset = async (member: GuildMember, presetName: PresetKey) => {
+ const where = and(
+ eq(appliedPresets.memberId, member.id),
+ eq(appliedPresets.preset, presetName),
+ eq(appliedPresets.guildId, member.guild.id),
+ )
+
+ const data = await database.query.appliedPresets.findFirst({ where })
+ if (!data) return false
+
+ const { callback } = await applyRolesUsingPreset(presetName, member, data.removedRoles)
+ await database.delete(appliedPresets).where(where).execute().then(callback)
+
+ return true
+}
+
+export const applyRolesUsingPreset = async (
+ presetName: string,
+ member: GuildMember,
+ removePresetGiveRoles?: string[],
+) => {
+ const preset = config.rolePresets?.guilds[member.guild.id]?.[presetName]
+ if (!preset) throw new Error(`The preset "${presetName}" does not exist for this server`)
+
+ const roles = new Set(member.roles.cache.keys())
+ const removed: string[] = []
+
+ // If removePresetGiveRoles is not provided, we're applying a preset
+ if (!removePresetGiveRoles) {
+ for (const role of preset.give) roles.add(role)
+ for (const role of preset.take) {
+ if (roles.has(role)) {
+ roles.delete(role)
+ removed.push(role)
+ }
+ }
+ } else {
+ const guildRoles = await member.guild.roles.fetch()
+ for (const role of preset.give) roles.delete(role)
+ for (const role of removePresetGiveRoles) if (guildRoles.has(role)) roles.add(role)
+ }
+
+ return {
+ removed,
+ callback: () => member.roles.set(Array.from(roles)),
+ }
+}
diff --git a/bots/discord/src/utils/duration.ts b/bots/discord/src/utils/duration.ts
new file mode 100644
index 0000000..43616fa
--- /dev/null
+++ b/bots/discord/src/utils/duration.ts
@@ -0,0 +1,25 @@
+import parse from 'parse-duration'
+
+parse[''] = parse['s']!
+parse['mo'] = parse['M'] = parse['month']!
+
+export const parseDuration = (duration: string, defaultUnit?: parse.Units) => {
+ const defaultUnitValue = parse['']!
+ if (defaultUnit) parse[''] = parse[defaultUnit]!
+ const result = parse(duration, 'ms') ?? Number.NaN
+ parse[''] = defaultUnitValue
+ return result
+}
+
+export const durationToString = (duration: number) => {
+ if (duration === 0) return '0s'
+
+ const days = Math.floor(duration / (24 * 60 * 60 * 1000))
+ const hours = Math.floor((duration % (24 * 60 * 60 * 1000)) / (60 * 60 * 1000))
+ const minutes = Math.floor((duration % (60 * 60 * 1000)) / (60 * 1000))
+ const seconds = Math.floor((duration % (60 * 1000)) / 1000)
+
+ return `${days ? `${days}d` : ''}${hours ? `${hours}h` : ''}${minutes ? `${minutes}m` : ''}${
+ seconds ? `${seconds}s` : ''
+ }`
+}
diff --git a/bots/discord/src/utils/fs.ts b/bots/discord/src/utils/fs.ts
new file mode 100644
index 0000000..b42f5fc
--- /dev/null
+++ b/bots/discord/src/utils/fs.ts
@@ -0,0 +1,33 @@
+import { readdirSync, writeFileSync } from 'fs'
+import { join, sep as pathSep, relative } from 'path'
+import { sep as posixPathSep } from 'path/posix'
+
+export const listAllFilesRecursive = (dir: string): string[] =>
+ readdirSync(dir, { recursive: true, withFileTypes: true })
+ .filter(x => x.isFile())
+ .map(x => join(x.parentPath, x.name).replaceAll(pathSep, posixPathSep))
+
+export const generateCommandsIndex = (dirPath: string) =>
+ generateIndexes(dirPath, (x, i) => `export { default as C${i} } from './${x}'`)
+
+export const generateEventsIndex = (dirPath: string) => generateIndexes(dirPath)
+
+const generateIndexes = async (
+ dirPath: string,
+ customMap?: (path: string, index: number) => string,
+ pathFilter?: (path: string) => boolean,
+) => {
+ const files = listAllFilesRecursive(dirPath)
+ .filter(x => x.endsWith('.ts') && !x.endsWith('index.ts') && (pathFilter ? pathFilter(x) : true))
+ .map(x => relative(dirPath, x).replaceAll(pathSep, posixPathSep))
+
+ writeFileSync(
+ join(dirPath, 'index.ts'),
+ `// AUTO-GENERATED BY A SCRIPT, DON'T TOUCH\n\n${files
+ .map((c, i) => {
+ const path = c.split('.').at(-2)!
+ return customMap ? customMap(path, i) : `import './${path}'`
+ })
+ .join('\n')}`,
+ )
+}
diff --git a/bots/discord/tsconfig.json b/bots/discord/tsconfig.json
new file mode 100755
index 0000000..22f6498
--- /dev/null
+++ b/bots/discord/tsconfig.json
@@ -0,0 +1,36 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "baseUrl": ".",
+ "outDir": "dist",
+ "module": "ESNext",
+ "target": "ESNext",
+ "lib": ["ESNext"],
+ "composite": false,
+ "exactOptionalPropertyTypes": false,
+ "esModuleInterop": true,
+ "allowJs": true,
+ "paths": {
+ "$/*": ["./src/*"],
+ "$constants": ["./src/constants"],
+ "$utils/*": ["./src/utils/*"],
+ "$classes": ["./src/classes/index.ts"],
+ "$classes/*": ["./src/classes/*"],
+ "$commands": ["./src/commands/index.ts"],
+ "$commands/*": ["./src/commands/*"]
+ },
+ "skipLibCheck": true,
+ "plugins": [
+ {
+ "transform": "typescript-transform-path-rewrite"
+ }
+ ]
+ },
+ "exclude": [
+ "node_modules",
+ "dist",
+ "./config.schema.ts",
+ "./drizzle.config.ts"
+ ],
+ "include": ["./src/**/*.ts", "./scripts/**/*.ts"]
+}
diff --git a/bun.lock b/bun.lock
new file mode 100644
index 0000000..f09a920
--- /dev/null
+++ b/bun.lock
@@ -0,0 +1,1885 @@
+{
+ "lockfileVersion": 1,
+ "workspaces": {
+ "": {
+ "name": "revanced-helper",
+ "devDependencies": {
+ "@anolilab/multi-semantic-release": "^1.1.10",
+ "@biomejs/biome": "^1.9.4",
+ "@codedependant/semantic-release-docker": "^5.1.0",
+ "@commitlint/cli": "^19.8.0",
+ "@commitlint/config-conventional": "^19.8.0",
+ "@saithodev/semantic-release-backmerge": "^4.0.1",
+ "@semantic-release/changelog": "^6.0.3",
+ "@semantic-release/exec": "^6.0.3",
+ "@semantic-release/git": "^10.0.1",
+ "@tsconfig/strictest": "^2.0.5",
+ "@types/bun": "^1.2.8",
+ "conventional-changelog-conventionalcommits": "^7.0.2",
+ "lefthook": "^1.11.6",
+ "portainer-service-webhook": "https://github.com/newarifrh/portainer-service-webhook#v1",
+ "semantic-release": "^24.2.3",
+ "turbo": "^2.5.0",
+ "typescript": "^5.8.2",
+ },
+ },
+ "apis/websocket": {
+ "name": "@revanced/bot-websocket-api",
+ "version": "1.0.0-dev.10",
+ "dependencies": {
+ "@revanced/bot-shared": "workspace:*",
+ "@sapphire/async-queue": "^1.5.5",
+ "chalk": "^5.4.1",
+ "tesseract.js": "^5.1.1",
+ "ws": "^8.18.1",
+ },
+ "devDependencies": {
+ "@types/ws": "^8.18.1",
+ "typed-emitter": "^2.1.0",
+ },
+ },
+ "bots/discord": {
+ "name": "@revanced/discord-bot",
+ "version": "1.0.0-dev.36",
+ "dependencies": {
+ "@discordjs/builders": "^1.10.1",
+ "@discordjs/rest": "^2.4.3",
+ "@revanced/bot-api": "workspace:*",
+ "@revanced/bot-shared": "workspace:*",
+ "chalk": "^5.4.1",
+ "decancer": "^3.2.8",
+ "discord.js": "^14.18.0",
+ "drizzle-orm": "^0.31.4",
+ "parse-duration": "^1.1.2",
+ },
+ "devDependencies": {
+ "@libsql/client": "^0.7.0",
+ "discord-api-types": "^0.37.119",
+ "drizzle-kit": "^0.22.8",
+ },
+ },
+ "packages/api": {
+ "name": "@revanced/bot-api",
+ "version": "0.1.0",
+ "dependencies": {
+ "@revanced/bot-shared": "workspace:*",
+ "ws": "^8.18.1",
+ },
+ "devDependencies": {
+ "@types/ws": "^8.18.1",
+ "typed-emitter": "^2.1.0",
+ },
+ },
+ "packages/shared": {
+ "name": "@revanced/bot-shared",
+ "version": "0.1.0",
+ "dependencies": {
+ "bson": "^6.8.0",
+ "chalk": "^5.3.0",
+ "tracer": "^1.3.0",
+ "valibot": "^0.30.0",
+ },
+ },
+ },
+ "trustedDependencies": [
+ "@revanced/discord-bot",
+ "esbuild",
+ "@biomejs/biome",
+ "lefthook",
+ ],
+ "patchedDependencies": {
+ "@semantic-release/npm@12.0.1": "patches/@semantic-release%2Fnpm@12.0.1.patch",
+ "drizzle-kit@0.22.8": "patches/drizzle-kit@0.22.8.patch",
+ },
+ "packages": {
+ "@actions/core": ["@actions/core@1.11.1", "", { "dependencies": { "@actions/exec": "^1.1.1", "@actions/http-client": "^2.0.1" } }, "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A=="],
+
+ "@actions/exec": ["@actions/exec@1.1.1", "", { "dependencies": { "@actions/io": "^1.0.1" } }, "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w=="],
+
+ "@actions/http-client": ["@actions/http-client@2.2.1", "", { "dependencies": { "tunnel": "^0.0.6", "undici": "^5.25.4" } }, "sha512-KhC/cZsq7f8I4LfZSJKgCvEwfkE8o1538VoBeoGzokVLLnbFDEAdFD3UhoMklxo2un9NJVBdANOresx7vTHlHw=="],
+
+ "@actions/io": ["@actions/io@1.1.3", "", {}, "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="],
+
+ "@anolilab/multi-semantic-release": ["@anolilab/multi-semantic-release@1.1.10", "", { "dependencies": { "@semrel-extra/topo": "^1.14.1", "blork": "^9.3.0", "cosmiconfig": "^9.0.0", "debug": "^4.4.0", "detect-indent": "^7.0.1", "detect-newline": "^4.0.1", "execa": "^9.5.2", "git-log-parser": "^1.2.1", "lodash-es": "^4.17.21", "resolve-from": "^5.0.0", "semver": "^7.7.1", "signale": "^1.4.0", "stream-buffers": "^3.0.3", "yargs": "^17.7.2" }, "peerDependencies": { "semantic-release": "^20.0 || ^21.0 || >=22.0.3" }, "os": [ "linux", "win32", "darwin", ], "bin": { "multi-semantic-release": "bin/cli.js" } }, "sha512-00eUBYDMEBWzZygcMYi7ek0gJJD2hKldSucDY4VVEbyd3K1tJU3N8Tmx6EZ2HYu7tzrlMLQGnHgbyrJA6TyZ0w=="],
+
+ "@babel/code-frame": ["@babel/code-frame@7.24.7", "", { "dependencies": { "@babel/highlight": "^7.24.7", "picocolors": "^1.0.0" } }, "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA=="],
+
+ "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.24.7", "", {}, "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w=="],
+
+ "@babel/highlight": ["@babel/highlight@7.24.7", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.24.7", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" } }, "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw=="],
+
+ "@biomejs/biome": ["@biomejs/biome@1.9.4", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "1.9.4", "@biomejs/cli-darwin-x64": "1.9.4", "@biomejs/cli-linux-arm64": "1.9.4", "@biomejs/cli-linux-arm64-musl": "1.9.4", "@biomejs/cli-linux-x64": "1.9.4", "@biomejs/cli-linux-x64-musl": "1.9.4", "@biomejs/cli-win32-arm64": "1.9.4", "@biomejs/cli-win32-x64": "1.9.4" }, "bin": { "biome": "bin/biome" } }, "sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog=="],
+
+ "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@1.9.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw=="],
+
+ "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@1.9.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg=="],
+
+ "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@1.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g=="],
+
+ "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@1.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA=="],
+
+ "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@1.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg=="],
+
+ "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@1.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg=="],
+
+ "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@1.9.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg=="],
+
+ "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@1.9.4", "", { "os": "win32", "cpu": "x64" }, "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA=="],
+
+ "@codedependant/semantic-release-docker": ["@codedependant/semantic-release-docker@5.1.0", "", { "dependencies": { "@actions/core": "^1.11.1", "@semantic-release/error": "^3.0.0", "debug": "^4.1.1", "execa": "^4.0.2", "handlebars": "^4.7.7", "semver": "^7.3.2" } }, "sha512-Ok37Hrj3y2AeZA4nBHzXNPR+twZHbAnGY2vXV3V3MC9xP676PnP67eBpzP5zLodxBXqRFKixo8QiQhQJ8nnXbQ=="],
+
+ "@colors/colors": ["@colors/colors@1.5.0", "", {}, "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ=="],
+
+ "@commitlint/cli": ["@commitlint/cli@19.8.0", "", { "dependencies": { "@commitlint/format": "^19.8.0", "@commitlint/lint": "^19.8.0", "@commitlint/load": "^19.8.0", "@commitlint/read": "^19.8.0", "@commitlint/types": "^19.8.0", "tinyexec": "^0.3.0", "yargs": "^17.0.0" }, "bin": { "commitlint": "./cli.js" } }, "sha512-t/fCrLVu+Ru01h0DtlgHZXbHV2Y8gKocTR5elDOqIRUzQd0/6hpt2VIWOj9b3NDo7y4/gfxeR2zRtXq/qO6iUg=="],
+
+ "@commitlint/config-conventional": ["@commitlint/config-conventional@19.8.0", "", { "dependencies": { "@commitlint/types": "^19.8.0", "conventional-changelog-conventionalcommits": "^7.0.2" } }, "sha512-9I2kKJwcAPwMoAj38hwqFXG0CzS2Kj+SAByPUQ0SlHTfb7VUhYVmo7G2w2tBrqmOf7PFd6MpZ/a1GQJo8na8kw=="],
+
+ "@commitlint/config-validator": ["@commitlint/config-validator@19.8.0", "", { "dependencies": { "@commitlint/types": "^19.8.0", "ajv": "^8.11.0" } }, "sha512-+r5ZvD/0hQC3w5VOHJhGcCooiAVdynFlCe2d6I9dU+PvXdV3O+fU4vipVg+6hyLbQUuCH82mz3HnT/cBQTYYuA=="],
+
+ "@commitlint/ensure": ["@commitlint/ensure@19.8.0", "", { "dependencies": { "@commitlint/types": "^19.8.0", "lodash.camelcase": "^4.3.0", "lodash.kebabcase": "^4.1.1", "lodash.snakecase": "^4.1.1", "lodash.startcase": "^4.4.0", "lodash.upperfirst": "^4.3.1" } }, "sha512-kNiNU4/bhEQ/wutI1tp1pVW1mQ0QbAjfPRo5v8SaxoVV+ARhkB8Wjg3BSseNYECPzWWfg/WDqQGIfV1RaBFQZg=="],
+
+ "@commitlint/execute-rule": ["@commitlint/execute-rule@19.8.0", "", {}, "sha512-fuLeI+EZ9x2v/+TXKAjplBJWI9CNrHnyi5nvUQGQt4WRkww/d95oVRsc9ajpt4xFrFmqMZkd/xBQHZDvALIY7A=="],
+
+ "@commitlint/format": ["@commitlint/format@19.8.0", "", { "dependencies": { "@commitlint/types": "^19.8.0", "chalk": "^5.3.0" } }, "sha512-EOpA8IERpQstxwp/WGnDArA7S+wlZDeTeKi98WMOvaDLKbjptuHWdOYYr790iO7kTCif/z971PKPI2PkWMfOxg=="],
+
+ "@commitlint/is-ignored": ["@commitlint/is-ignored@19.8.0", "", { "dependencies": { "@commitlint/types": "^19.8.0", "semver": "^7.6.0" } }, "sha512-L2Jv9yUg/I+jF3zikOV0rdiHUul9X3a/oU5HIXhAJLE2+TXTnEBfqYP9G5yMw/Yb40SnR764g4fyDK6WR2xtpw=="],
+
+ "@commitlint/lint": ["@commitlint/lint@19.8.0", "", { "dependencies": { "@commitlint/is-ignored": "^19.8.0", "@commitlint/parse": "^19.8.0", "@commitlint/rules": "^19.8.0", "@commitlint/types": "^19.8.0" } }, "sha512-+/NZKyWKSf39FeNpqhfMebmaLa1P90i1Nrb1SrA7oSU5GNN/lksA4z6+ZTnsft01YfhRZSYMbgGsARXvkr/VLQ=="],
+
+ "@commitlint/load": ["@commitlint/load@19.8.0", "", { "dependencies": { "@commitlint/config-validator": "^19.8.0", "@commitlint/execute-rule": "^19.8.0", "@commitlint/resolve-extends": "^19.8.0", "@commitlint/types": "^19.8.0", "chalk": "^5.3.0", "cosmiconfig": "^9.0.0", "cosmiconfig-typescript-loader": "^6.1.0", "lodash.isplainobject": "^4.0.6", "lodash.merge": "^4.6.2", "lodash.uniq": "^4.5.0" } }, "sha512-4rvmm3ff81Sfb+mcWT5WKlyOa+Hd33WSbirTVUer0wjS1Hv/Hzr07Uv1ULIV9DkimZKNyOwXn593c+h8lsDQPQ=="],
+
+ "@commitlint/message": ["@commitlint/message@19.8.0", "", {}, "sha512-qs/5Vi9bYjf+ZV40bvdCyBn5DvbuelhR6qewLE8Bh476F7KnNyLfdM/ETJ4cp96WgeeHo6tesA2TMXS0sh5X4A=="],
+
+ "@commitlint/parse": ["@commitlint/parse@19.8.0", "", { "dependencies": { "@commitlint/types": "^19.8.0", "conventional-changelog-angular": "^7.0.0", "conventional-commits-parser": "^5.0.0" } }, "sha512-YNIKAc4EXvNeAvyeEnzgvm1VyAe0/b3Wax7pjJSwXuhqIQ1/t2hD3OYRXb6D5/GffIvaX82RbjD+nWtMZCLL7Q=="],
+
+ "@commitlint/read": ["@commitlint/read@19.8.0", "", { "dependencies": { "@commitlint/top-level": "^19.8.0", "@commitlint/types": "^19.8.0", "git-raw-commits": "^4.0.0", "minimist": "^1.2.8", "tinyexec": "^0.3.0" } }, "sha512-6ywxOGYajcxK1y1MfzrOnwsXO6nnErna88gRWEl3qqOOP8MDu/DTeRkGLXBFIZuRZ7mm5yyxU5BmeUvMpNte5w=="],
+
+ "@commitlint/resolve-extends": ["@commitlint/resolve-extends@19.8.0", "", { "dependencies": { "@commitlint/config-validator": "^19.8.0", "@commitlint/types": "^19.8.0", "global-directory": "^4.0.1", "import-meta-resolve": "^4.0.0", "lodash.mergewith": "^4.6.2", "resolve-from": "^5.0.0" } }, "sha512-CLanRQwuG2LPfFVvrkTrBR/L/DMy3+ETsgBqW1OvRxmzp/bbVJW0Xw23LnnExgYcsaFtos967lul1CsbsnJlzQ=="],
+
+ "@commitlint/rules": ["@commitlint/rules@19.8.0", "", { "dependencies": { "@commitlint/ensure": "^19.8.0", "@commitlint/message": "^19.8.0", "@commitlint/to-lines": "^19.8.0", "@commitlint/types": "^19.8.0" } }, "sha512-IZ5IE90h6DSWNuNK/cwjABLAKdy8tP8OgGVGbXe1noBEX5hSsu00uRlLu6JuruiXjWJz2dZc+YSw3H0UZyl/mA=="],
+
+ "@commitlint/to-lines": ["@commitlint/to-lines@19.8.0", "", {}, "sha512-3CKLUw41Cur8VMjh16y8LcsOaKbmQjAKCWlXx6B0vOUREplp6em9uIVhI8Cv934qiwkbi2+uv+mVZPnXJi1o9A=="],
+
+ "@commitlint/top-level": ["@commitlint/top-level@19.8.0", "", { "dependencies": { "find-up": "^7.0.0" } }, "sha512-Rphgoc/omYZisoNkcfaBRPQr4myZEHhLPx2/vTXNLjiCw4RgfPR1wEgUpJ9OOmDCiv5ZyIExhprNLhteqH4FuQ=="],
+
+ "@commitlint/types": ["@commitlint/types@19.8.0", "", { "dependencies": { "@types/conventional-commits-parser": "^5.0.0", "chalk": "^5.3.0" } }, "sha512-LRjP623jPyf3Poyfb0ohMj8I3ORyBDOwXAgxxVPbSD0unJuW2mJWeiRfaQinjtccMqC5Wy1HOMfa4btKjbNxbg=="],
+
+ "@discordjs/builders": ["@discordjs/builders@1.10.1", "", { "dependencies": { "@discordjs/formatters": "^0.6.0", "@discordjs/util": "^1.1.1", "@sapphire/shapeshift": "^4.0.0", "discord-api-types": "^0.37.119", "fast-deep-equal": "^3.1.3", "ts-mixer": "^6.0.4", "tslib": "^2.6.3" } }, "sha512-OWo1fY4ztL1/M/DUyRPShB4d/EzVfuUvPTRRHRIt/YxBrUYSz0a+JicD5F5zHFoNs2oTuWavxCOVFV1UljHTng=="],
+
+ "@discordjs/collection": ["@discordjs/collection@2.1.1", "", {}, "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="],
+
+ "@discordjs/formatters": ["@discordjs/formatters@0.6.0", "", { "dependencies": { "discord-api-types": "^0.37.114" } }, "sha512-YIruKw4UILt/ivO4uISmrGq2GdMY6EkoTtD0oS0GvkJFRZbTSdPhzYiUILbJ/QslsvC9H9nTgGgnarnIl4jMfw=="],
+
+ "@discordjs/rest": ["@discordjs/rest@2.4.3", "", { "dependencies": { "@discordjs/collection": "^2.1.1", "@discordjs/util": "^1.1.1", "@sapphire/async-queue": "^1.5.3", "@sapphire/snowflake": "^3.5.3", "@vladfrangu/async_event_emitter": "^2.4.6", "discord-api-types": "^0.37.119", "magic-bytes.js": "^1.10.0", "tslib": "^2.6.3", "undici": "6.21.1" } }, "sha512-+SO4RKvWsM+y8uFHgYQrcTl/3+cY02uQOH7/7bKbVZsTfrfpoE62o5p+mmV+s7FVhTX82/kQUGGbu4YlV60RtA=="],
+
+ "@discordjs/util": ["@discordjs/util@1.1.1", "", {}, "sha512-eddz6UnOBEB1oITPinyrB2Pttej49M9FZQY8NxgEvc3tq6ZICZ19m70RsmzRdDHk80O9NoYN/25AqJl8vPVf/g=="],
+
+ "@discordjs/ws": ["@discordjs/ws@1.2.1", "", { "dependencies": { "@discordjs/collection": "^2.1.0", "@discordjs/rest": "^2.4.3", "@discordjs/util": "^1.1.0", "@sapphire/async-queue": "^1.5.2", "@types/ws": "^8.5.10", "@vladfrangu/async_event_emitter": "^2.2.4", "discord-api-types": "^0.37.119", "tslib": "^2.6.2", "ws": "^8.17.0" } }, "sha512-PBvenhZG56a6tMWF/f4P6f4GxZKJTBG95n7aiGSPTnodmz4N5g60t79rSIAq7ywMbv8A4jFtexMruH+oe51aQQ=="],
+
+ "@esbuild-kit/core-utils": ["@esbuild-kit/core-utils@3.3.2", "", { "dependencies": { "esbuild": "~0.18.20", "source-map-support": "^0.5.21" } }, "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ=="],
+
+ "@esbuild-kit/esm-loader": ["@esbuild-kit/esm-loader@2.6.5", "", { "dependencies": { "@esbuild-kit/core-utils": "^3.3.2", "get-tsconfig": "^4.7.0" } }, "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA=="],
+
+ "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.19.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA=="],
+
+ "@esbuild/android-arm": ["@esbuild/android-arm@0.19.12", "", { "os": "android", "cpu": "arm" }, "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w=="],
+
+ "@esbuild/android-arm64": ["@esbuild/android-arm64@0.19.12", "", { "os": "android", "cpu": "arm64" }, "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA=="],
+
+ "@esbuild/android-x64": ["@esbuild/android-x64@0.19.12", "", { "os": "android", "cpu": "x64" }, "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew=="],
+
+ "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.19.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g=="],
+
+ "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.19.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A=="],
+
+ "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.19.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA=="],
+
+ "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.19.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg=="],
+
+ "@esbuild/linux-arm": ["@esbuild/linux-arm@0.19.12", "", { "os": "linux", "cpu": "arm" }, "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w=="],
+
+ "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.19.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA=="],
+
+ "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.19.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA=="],
+
+ "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA=="],
+
+ "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w=="],
+
+ "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.19.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg=="],
+
+ "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg=="],
+
+ "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.19.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg=="],
+
+ "@esbuild/linux-x64": ["@esbuild/linux-x64@0.19.12", "", { "os": "linux", "cpu": "x64" }, "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg=="],
+
+ "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.19.12", "", { "os": "none", "cpu": "x64" }, "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA=="],
+
+ "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.19.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw=="],
+
+ "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.19.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA=="],
+
+ "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.19.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A=="],
+
+ "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.19.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ=="],
+
+ "@esbuild/win32-x64": ["@esbuild/win32-x64@0.19.12", "", { "os": "win32", "cpu": "x64" }, "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA=="],
+
+ "@fastify/busboy": ["@fastify/busboy@2.1.1", "", {}, "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA=="],
+
+ "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="],
+
+ "@isaacs/string-locale-compare": ["@isaacs/string-locale-compare@1.1.0", "", {}, "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ=="],
+
+ "@libsql/client": ["@libsql/client@0.7.0", "", { "dependencies": { "@libsql/core": "^0.7.0", "@libsql/hrana-client": "^0.6.0", "js-base64": "^3.7.5", "libsql": "^0.3.10", "promise-limit": "^2.7.0" } }, "sha512-1aLDtWzsErr68GZ640TVyOLkL/+lB2YK8cYvJIfiI7Mt+DEPB22Jkoz2QfBDg5PVGX/efeRHog2j/oVbUhxO8Q=="],
+
+ "@libsql/core": ["@libsql/core@0.7.0", "", { "dependencies": { "js-base64": "^3.7.5" } }, "sha512-hCYfXa0S4t9CJtxZIWacboylrcx94ZQO0dEngH4f0f/LHg6ymHSZiubbojAwD7tNy94ahICoGPjEi6aEIyhlcQ=="],
+
+ "@libsql/darwin-arm64": ["@libsql/darwin-arm64@0.3.19", "", { "os": "darwin", "cpu": "arm64" }, "sha512-rmOqsLcDI65zzxlUOoEiPJLhqmbFsZF6p4UJQ2kMqB+Kc0Rt5/A1OAdOZ/Wo8fQfJWjR1IbkbpEINFioyKf+nQ=="],
+
+ "@libsql/darwin-x64": ["@libsql/darwin-x64@0.3.19", "", { "os": "darwin", "cpu": "x64" }, "sha512-q9O55B646zU+644SMmOQL3FIfpmEvdWpRpzubwFc2trsa+zoBlSkHuzU9v/C+UNoPHQVRMP7KQctJ455I/h/xw=="],
+
+ "@libsql/hrana-client": ["@libsql/hrana-client@0.6.2", "", { "dependencies": { "@libsql/isomorphic-fetch": "^0.2.1", "@libsql/isomorphic-ws": "^0.1.5", "js-base64": "^3.7.5", "node-fetch": "^3.3.2" } }, "sha512-MWxgD7mXLNf9FXXiM0bc90wCjZSpErWKr5mGza7ERy2FJNNMXd7JIOv+DepBA1FQTIfI8TFO4/QDYgaQC0goNw=="],
+
+ "@libsql/isomorphic-fetch": ["@libsql/isomorphic-fetch@0.2.1", "", {}, "sha512-Sv07QP1Aw8A5OOrmKgRUBKe2fFhF2hpGJhtHe3d1aRnTESZCGkn//0zDycMKTGamVWb3oLYRroOsCV8Ukes9GA=="],
+
+ "@libsql/isomorphic-ws": ["@libsql/isomorphic-ws@0.1.5", "", { "dependencies": { "@types/ws": "^8.5.4", "ws": "^8.13.0" } }, "sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg=="],
+
+ "@libsql/linux-arm64-gnu": ["@libsql/linux-arm64-gnu@0.3.19", "", { "os": "linux", "cpu": "arm64" }, "sha512-mgeAUU1oqqh57k7I3cQyU6Trpdsdt607eFyEmH5QO7dv303ti+LjUvh1pp21QWV6WX7wZyjeJV1/VzEImB+jRg=="],
+
+ "@libsql/linux-arm64-musl": ["@libsql/linux-arm64-musl@0.3.19", "", { "os": "linux", "cpu": "arm64" }, "sha512-VEZtxghyK6zwGzU9PHohvNxthruSxBEnRrX7BSL5jQ62tN4n2JNepJ6SdzXp70pdzTfwroOj/eMwiPt94gkVRg=="],
+
+ "@libsql/linux-x64-gnu": ["@libsql/linux-x64-gnu@0.3.19", "", { "os": "linux", "cpu": "x64" }, "sha512-2t/J7LD5w2f63wGihEO+0GxfTyYIyLGEvTFEsMO16XI5o7IS9vcSHrxsvAJs4w2Pf907uDjmc7fUfMg6L82BrQ=="],
+
+ "@libsql/linux-x64-musl": ["@libsql/linux-x64-musl@0.3.19", "", { "os": "linux", "cpu": "x64" }, "sha512-BLsXyJaL8gZD8+3W2LU08lDEd9MIgGds0yPy5iNPp8tfhXx3pV/Fge2GErN0FC+nzt4DYQtjL+A9GUMglQefXQ=="],
+
+ "@libsql/win32-x64-msvc": ["@libsql/win32-x64-msvc@0.3.19", "", { "os": "win32", "cpu": "x64" }, "sha512-ay1X9AobE4BpzG0XPw1gplyLZPGHIgJOovvW23gUrukRegiUP62uzhpRbKNogLlUOynyXeq//prHgPXiebUfWg=="],
+
+ "@neon-rs/load": ["@neon-rs/load@0.0.4", "", {}, "sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw=="],
+
+ "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
+
+ "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="],
+
+ "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
+
+ "@npmcli/agent": ["@npmcli/agent@2.2.2", "", { "dependencies": { "agent-base": "^7.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.1", "lru-cache": "^10.0.1", "socks-proxy-agent": "^8.0.3" } }, "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og=="],
+
+ "@npmcli/arborist": ["@npmcli/arborist@7.5.4", "", { "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/fs": "^3.1.1", "@npmcli/installed-package-contents": "^2.1.0", "@npmcli/map-workspaces": "^3.0.2", "@npmcli/metavuln-calculator": "^7.1.1", "@npmcli/name-from-folder": "^2.0.0", "@npmcli/node-gyp": "^3.0.0", "@npmcli/package-json": "^5.1.0", "@npmcli/query": "^3.1.0", "@npmcli/redact": "^2.0.0", "@npmcli/run-script": "^8.1.0", "bin-links": "^4.0.4", "cacache": "^18.0.3", "common-ancestor-path": "^1.0.1", "hosted-git-info": "^7.0.2", "json-parse-even-better-errors": "^3.0.2", "json-stringify-nice": "^1.1.4", "lru-cache": "^10.2.2", "minimatch": "^9.0.4", "nopt": "^7.2.1", "npm-install-checks": "^6.2.0", "npm-package-arg": "^11.0.2", "npm-pick-manifest": "^9.0.1", "npm-registry-fetch": "^17.0.1", "pacote": "^18.0.6", "parse-conflict-json": "^3.0.0", "proc-log": "^4.2.0", "proggy": "^2.0.0", "promise-all-reject-late": "^1.0.0", "promise-call-limit": "^3.0.1", "read-package-json-fast": "^3.0.2", "semver": "^7.3.7", "ssri": "^10.0.6", "treeverse": "^3.0.0", "walk-up-path": "^3.0.1" }, "bin": { "arborist": "bin/index.js" } }, "sha512-nWtIc6QwwoUORCRNzKx4ypHqCk3drI+5aeYdMTQQiRCcn4lOOgfQh7WyZobGYTxXPSq1VwV53lkpN/BRlRk08g=="],
+
+ "@npmcli/config": ["@npmcli/config@8.3.4", "", { "dependencies": { "@npmcli/map-workspaces": "^3.0.2", "@npmcli/package-json": "^5.1.1", "ci-info": "^4.0.0", "ini": "^4.1.2", "nopt": "^7.2.1", "proc-log": "^4.2.0", "semver": "^7.3.5", "walk-up-path": "^3.0.1" } }, "sha512-01rtHedemDNhUXdicU7s+QYz/3JyV5Naj84cvdXGH4mgCdL+agmSYaLF4LUG4vMCLzhBO8YtS0gPpH1FGvbgAw=="],
+
+ "@npmcli/fs": ["@npmcli/fs@3.1.1", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg=="],
+
+ "@npmcli/git": ["@npmcli/git@5.0.8", "", { "dependencies": { "@npmcli/promise-spawn": "^7.0.0", "ini": "^4.1.3", "lru-cache": "^10.0.1", "npm-pick-manifest": "^9.0.0", "proc-log": "^4.0.0", "promise-inflight": "^1.0.1", "promise-retry": "^2.0.1", "semver": "^7.3.5", "which": "^4.0.0" } }, "sha512-liASfw5cqhjNW9UFd+ruwwdEf/lbOAQjLL2XY2dFW/bkJheXDYZgOyul/4gVvEV4BWkTXjYGmDqMw9uegdbJNQ=="],
+
+ "@npmcli/installed-package-contents": ["@npmcli/installed-package-contents@2.1.0", "", { "dependencies": { "npm-bundled": "^3.0.0", "npm-normalize-package-bin": "^3.0.0" }, "bin": { "installed-package-contents": "bin/index.js" } }, "sha512-c8UuGLeZpm69BryRykLuKRyKFZYJsZSCT4aVY5ds4omyZqJ172ApzgfKJ5eV/r3HgLdUYgFVe54KSFVjKoe27w=="],
+
+ "@npmcli/map-workspaces": ["@npmcli/map-workspaces@3.0.6", "", { "dependencies": { "@npmcli/name-from-folder": "^2.0.0", "glob": "^10.2.2", "minimatch": "^9.0.0", "read-package-json-fast": "^3.0.0" } }, "sha512-tkYs0OYnzQm6iIRdfy+LcLBjcKuQCeE5YLb8KnrIlutJfheNaPvPpgoFEyEFgbjzl5PLZ3IA/BWAwRU0eHuQDA=="],
+
+ "@npmcli/metavuln-calculator": ["@npmcli/metavuln-calculator@7.1.1", "", { "dependencies": { "cacache": "^18.0.0", "json-parse-even-better-errors": "^3.0.0", "pacote": "^18.0.0", "proc-log": "^4.1.0", "semver": "^7.3.5" } }, "sha512-Nkxf96V0lAx3HCpVda7Vw4P23RILgdi/5K1fmj2tZkWIYLpXAN8k2UVVOsW16TsS5F8Ws2I7Cm+PU1/rsVF47g=="],
+
+ "@npmcli/name-from-folder": ["@npmcli/name-from-folder@2.0.0", "", {}, "sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg=="],
+
+ "@npmcli/node-gyp": ["@npmcli/node-gyp@3.0.0", "", {}, "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA=="],
+
+ "@npmcli/package-json": ["@npmcli/package-json@5.2.0", "", { "dependencies": { "@npmcli/git": "^5.0.0", "glob": "^10.2.2", "hosted-git-info": "^7.0.0", "json-parse-even-better-errors": "^3.0.0", "normalize-package-data": "^6.0.0", "proc-log": "^4.0.0", "semver": "^7.5.3" } }, "sha512-qe/kiqqkW0AGtvBjL8TJKZk/eBBSpnJkUWvHdQ9jM2lKHXRYYJuyNpJPlJw3c8QjC2ow6NZYiLExhUaeJelbxQ=="],
+
+ "@npmcli/promise-spawn": ["@npmcli/promise-spawn@7.0.2", "", { "dependencies": { "which": "^4.0.0" } }, "sha512-xhfYPXoV5Dy4UkY0D+v2KkwvnDfiA/8Mt3sWCGI/hM03NsYIH8ZaG6QzS9x7pje5vHZBZJ2v6VRFVTWACnqcmQ=="],
+
+ "@npmcli/query": ["@npmcli/query@3.1.0", "", { "dependencies": { "postcss-selector-parser": "^6.0.10" } }, "sha512-C/iR0tk7KSKGldibYIB9x8GtO/0Bd0I2mhOaDb8ucQL/bQVTmGoeREaFj64Z5+iCBRf3dQfed0CjJL7I8iTkiQ=="],
+
+ "@npmcli/redact": ["@npmcli/redact@2.0.1", "", {}, "sha512-YgsR5jCQZhVmTJvjduTOIHph0L73pK8xwMVaDY0PatySqVM9AZj93jpoXYSJqfHFxFkN9dmqTw6OiqExsS3LPw=="],
+
+ "@npmcli/run-script": ["@npmcli/run-script@8.1.0", "", { "dependencies": { "@npmcli/node-gyp": "^3.0.0", "@npmcli/package-json": "^5.0.0", "@npmcli/promise-spawn": "^7.0.0", "node-gyp": "^10.0.0", "proc-log": "^4.0.0", "which": "^4.0.0" } }, "sha512-y7efHHwghQfk28G2z3tlZ67pLG0XdfYbcVG26r7YIXALRsrVQcTq4/tdenSmdOrEsNahIYA/eh8aEVROWGFUDg=="],
+
+ "@octokit/auth-token": ["@octokit/auth-token@5.1.1", "", {}, "sha512-rh3G3wDO8J9wSjfI436JUKzHIxq8NaiL0tVeB2aXmG6p/9859aUOAjA9pmSPNGGZxfwmaJ9ozOJImuNVJdpvbA=="],
+
+ "@octokit/core": ["@octokit/core@6.1.2", "", { "dependencies": { "@octokit/auth-token": "^5.0.0", "@octokit/graphql": "^8.0.0", "@octokit/request": "^9.0.0", "@octokit/request-error": "^6.0.1", "@octokit/types": "^13.0.0", "before-after-hook": "^3.0.2", "universal-user-agent": "^7.0.0" } }, "sha512-hEb7Ma4cGJGEUNOAVmyfdB/3WirWMg5hDuNFVejGEDFqupeOysLc2sG6HJxY2etBp5YQu5Wtxwi020jS9xlUwg=="],
+
+ "@octokit/endpoint": ["@octokit/endpoint@10.1.1", "", { "dependencies": { "@octokit/types": "^13.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-JYjh5rMOwXMJyUpj028cu0Gbp7qe/ihxfJMLc8VZBMMqSwLgOxDI1911gV4Enl1QSavAQNJcwmwBF9M0VvLh6Q=="],
+
+ "@octokit/graphql": ["@octokit/graphql@8.1.1", "", { "dependencies": { "@octokit/request": "^9.0.0", "@octokit/types": "^13.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-ukiRmuHTi6ebQx/HFRCXKbDlOh/7xEV6QUXaE7MJEKGNAncGI/STSbOkl12qVXZrfZdpXctx5O9X1AIaebiDBg=="],
+
+ "@octokit/openapi-types": ["@octokit/openapi-types@22.2.0", "", {}, "sha512-QBhVjcUa9W7Wwhm6DBFu6ZZ+1/t/oYxqc2tp81Pi41YNuJinbFRx8B133qVOrAaBbF7D/m0Et6f9/pZt9Rc+tg=="],
+
+ "@octokit/plugin-paginate-rest": ["@octokit/plugin-paginate-rest@11.3.3", "", { "dependencies": { "@octokit/types": "^13.5.0" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-o4WRoOJZlKqEEgj+i9CpcmnByvtzoUYC6I8PD2SA95M+BJ2x8h7oLcVOg9qcowWXBOdcTRsMZiwvM3EyLm9AfA=="],
+
+ "@octokit/plugin-retry": ["@octokit/plugin-retry@7.1.1", "", { "dependencies": { "@octokit/request-error": "^6.0.0", "@octokit/types": "^13.0.0", "bottleneck": "^2.15.3" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-G9Ue+x2odcb8E1XIPhaFBnTTIrrUDfXN05iFXiqhR+SeeeDMMILcAnysOsxUpEWcQp2e5Ft397FCXTcPkiPkLw=="],
+
+ "@octokit/plugin-throttling": ["@octokit/plugin-throttling@9.3.1", "", { "dependencies": { "@octokit/types": "^13.0.0", "bottleneck": "^2.15.3" }, "peerDependencies": { "@octokit/core": "^6.0.0" } }, "sha512-Qd91H4liUBhwLB2h6jZ99bsxoQdhgPk6TdwnClPyTBSDAdviGPceViEgUwj+pcQDmB/rfAXAXK7MTochpHM3yQ=="],
+
+ "@octokit/request": ["@octokit/request@9.1.3", "", { "dependencies": { "@octokit/endpoint": "^10.0.0", "@octokit/request-error": "^6.0.1", "@octokit/types": "^13.1.0", "universal-user-agent": "^7.0.2" } }, "sha512-V+TFhu5fdF3K58rs1pGUJIDH5RZLbZm5BI+MNF+6o/ssFNT4vWlCh/tVpF3NxGtP15HUxTTMUbsG5llAuU2CZA=="],
+
+ "@octokit/request-error": ["@octokit/request-error@6.1.4", "", { "dependencies": { "@octokit/types": "^13.0.0" } }, "sha512-VpAhIUxwhWZQImo/dWAN/NpPqqojR6PSLgLYAituLM6U+ddx9hCioFGwBr5Mi+oi5CLeJkcAs3gJ0PYYzU6wUg=="],
+
+ "@octokit/types": ["@octokit/types@13.5.0", "", { "dependencies": { "@octokit/openapi-types": "^22.2.0" } }, "sha512-HdqWTf5Z3qwDVlzCrP8UJquMwunpDiMPt5er+QjGzL4hqr/vBVY/MauQgS1xWxCDT1oMx1EULyqxncdCY/NVSQ=="],
+
+ "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
+
+ "@pnpm/config.env-replace": ["@pnpm/config.env-replace@1.1.0", "", {}, "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w=="],
+
+ "@pnpm/network.ca-file": ["@pnpm/network.ca-file@1.0.2", "", { "dependencies": { "graceful-fs": "4.2.10" } }, "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA=="],
+
+ "@pnpm/npm-conf": ["@pnpm/npm-conf@2.2.2", "", { "dependencies": { "@pnpm/config.env-replace": "^1.1.0", "@pnpm/network.ca-file": "^1.0.1", "config-chain": "^1.1.11" } }, "sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA=="],
+
+ "@revanced/bot-api": ["@revanced/bot-api@workspace:packages/api"],
+
+ "@revanced/bot-shared": ["@revanced/bot-shared@workspace:packages/shared"],
+
+ "@revanced/bot-websocket-api": ["@revanced/bot-websocket-api@workspace:apis/websocket"],
+
+ "@revanced/discord-bot": ["@revanced/discord-bot@workspace:bots/discord"],
+
+ "@saithodev/semantic-release-backmerge": ["@saithodev/semantic-release-backmerge@4.0.1", "", { "dependencies": { "@semantic-release/error": "^3.0.0", "aggregate-error": "^3.1.0", "debug": "^4.3.4", "execa": "^5.1.1", "lodash": "^4.17.21", "semantic-release": "^22.0.7" } }, "sha512-WDsU28YrXSLx0xny7FgFlEk8DCKGcj6OOhA+4Q9k3te1jJD1GZuqY8sbIkVQaw9cqJ7CT+fCZUN6QDad8JW4Dg=="],
+
+ "@sapphire/async-queue": ["@sapphire/async-queue@1.5.5", "", {}, "sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg=="],
+
+ "@sapphire/shapeshift": ["@sapphire/shapeshift@4.0.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "lodash": "^4.17.21" } }, "sha512-d9dUmWVA7MMiKobL3VpLF8P2aeanRTu6ypG2OIaEv/ZHH/SUQ2iHOVyi5wAPjQ+HmnMuL0whK9ez8I/raWbtIg=="],
+
+ "@sapphire/snowflake": ["@sapphire/snowflake@3.5.3", "", {}, "sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ=="],
+
+ "@sec-ant/readable-stream": ["@sec-ant/readable-stream@0.4.1", "", {}, "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg=="],
+
+ "@semantic-release/changelog": ["@semantic-release/changelog@6.0.3", "", { "dependencies": { "@semantic-release/error": "^3.0.0", "aggregate-error": "^3.0.0", "fs-extra": "^11.0.0", "lodash": "^4.17.4" }, "peerDependencies": { "semantic-release": ">=18.0.0" } }, "sha512-dZuR5qByyfe3Y03TpmCvAxCyTnp7r5XwtHRf/8vD9EAn4ZWbavUX8adMtXYzE86EVh0gyLA7lm5yW4IV30XUag=="],
+
+ "@semantic-release/commit-analyzer": ["@semantic-release/commit-analyzer@13.0.0", "", { "dependencies": { "conventional-changelog-angular": "^8.0.0", "conventional-changelog-writer": "^8.0.0", "conventional-commits-filter": "^5.0.0", "conventional-commits-parser": "^6.0.0", "debug": "^4.0.0", "import-from-esm": "^1.0.3", "lodash-es": "^4.17.21", "micromatch": "^4.0.2" }, "peerDependencies": { "semantic-release": ">=20.1.0" } }, "sha512-KtXWczvTAB1ZFZ6B4O+w8HkfYm/OgQb1dUGNFZtDgQ0csggrmkq8sTxhd+lwGF8kMb59/RnG9o4Tn7M/I8dQ9Q=="],
+
+ "@semantic-release/error": ["@semantic-release/error@3.0.0", "", {}, "sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw=="],
+
+ "@semantic-release/exec": ["@semantic-release/exec@6.0.3", "", { "dependencies": { "@semantic-release/error": "^3.0.0", "aggregate-error": "^3.0.0", "debug": "^4.0.0", "execa": "^5.0.0", "lodash": "^4.17.4", "parse-json": "^5.0.0" }, "peerDependencies": { "semantic-release": ">=18.0.0" } }, "sha512-bxAq8vLOw76aV89vxxICecEa8jfaWwYITw6X74zzlO0mc/Bgieqx9kBRz9z96pHectiTAtsCwsQcUyLYWnp3VQ=="],
+
+ "@semantic-release/git": ["@semantic-release/git@10.0.1", "", { "dependencies": { "@semantic-release/error": "^3.0.0", "aggregate-error": "^3.0.0", "debug": "^4.0.0", "dir-glob": "^3.0.0", "execa": "^5.0.0", "lodash": "^4.17.4", "micromatch": "^4.0.0", "p-reduce": "^2.0.0" }, "peerDependencies": { "semantic-release": ">=18.0.0" } }, "sha512-eWrx5KguUcU2wUPaO6sfvZI0wPafUKAMNC18aXY4EnNcrZL86dEmpNVnC9uMpGZkmZJ9EfCVJBQx4pV4EMGT1w=="],
+
+ "@semantic-release/github": ["@semantic-release/github@11.0.0", "", { "dependencies": { "@octokit/core": "^6.0.0", "@octokit/plugin-paginate-rest": "^11.0.0", "@octokit/plugin-retry": "^7.0.0", "@octokit/plugin-throttling": "^9.0.0", "@semantic-release/error": "^4.0.0", "aggregate-error": "^5.0.0", "debug": "^4.3.4", "dir-glob": "^3.0.1", "globby": "^14.0.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", "issue-parser": "^7.0.0", "lodash-es": "^4.17.21", "mime": "^4.0.0", "p-filter": "^4.0.0", "url-join": "^5.0.0" }, "peerDependencies": { "semantic-release": ">=24.1.0" } }, "sha512-Uon6G6gJD8U1JNvPm7X0j46yxNRJ8Ui6SgK4Zw5Ktu8RgjEft3BGn+l/RX1TTzhhO3/uUcKuqM+/9/ETFxWS/Q=="],
+
+ "@semantic-release/npm": ["@semantic-release/npm@12.0.1", "", { "dependencies": { "@semantic-release/error": "^4.0.0", "aggregate-error": "^5.0.0", "execa": "^9.0.0", "fs-extra": "^11.0.0", "lodash-es": "^4.17.21", "nerf-dart": "^1.0.0", "normalize-url": "^8.0.0", "npm": "^10.5.0", "rc": "^1.2.8", "read-pkg": "^9.0.0", "registry-auth-token": "^5.0.0", "semver": "^7.1.2", "tempy": "^3.0.0" }, "peerDependencies": { "semantic-release": ">=20.1.0" } }, "sha512-/6nntGSUGK2aTOI0rHPwY3ZjgY9FkXmEHbW9Kr+62NVOsyqpKKeP0lrCH+tphv+EsNdJNmqqwijTEnVWUMQ2Nw=="],
+
+ "@semantic-release/release-notes-generator": ["@semantic-release/release-notes-generator@14.0.1", "", { "dependencies": { "conventional-changelog-angular": "^8.0.0", "conventional-changelog-writer": "^8.0.0", "conventional-commits-filter": "^5.0.0", "conventional-commits-parser": "^6.0.0", "debug": "^4.0.0", "get-stream": "^7.0.0", "import-from-esm": "^1.0.3", "into-stream": "^7.0.0", "lodash-es": "^4.17.21", "read-package-up": "^11.0.0" }, "peerDependencies": { "semantic-release": ">=20.1.0" } }, "sha512-K0w+5220TM4HZTthE5dDpIuFrnkN1NfTGPidJFm04ULT1DEZ9WG89VNXN7F0c+6nMEpWgqmPvb7vY7JkB2jyyA=="],
+
+ "@semrel-extra/topo": ["@semrel-extra/topo@1.14.1", "", { "dependencies": { "fast-glob": "^3.3.2", "js-yaml": "^4.1.0", "toposource": "^1.2.0" } }, "sha512-V7hlOQoBXgqLSa4ai9S0LGOO7cKTqRu5dh0T83xfE+VqZQmDkuRm956ooJ2/M8y62kWIxS2VEfePnEoB74x6fg=="],
+
+ "@sigstore/bundle": ["@sigstore/bundle@2.3.2", "", { "dependencies": { "@sigstore/protobuf-specs": "^0.3.2" } }, "sha512-wueKWDk70QixNLB363yHc2D2ItTgYiMTdPwK8D9dKQMR3ZQ0c35IxP5xnwQ8cNLoCgCRcHf14kE+CLIvNX1zmA=="],
+
+ "@sigstore/core": ["@sigstore/core@1.1.0", "", {}, "sha512-JzBqdVIyqm2FRQCulY6nbQzMpJJpSiJ8XXWMhtOX9eKgaXXpfNOF53lzQEjIydlStnd/eFtuC1dW4VYdD93oRg=="],
+
+ "@sigstore/protobuf-specs": ["@sigstore/protobuf-specs@0.3.2", "", {}, "sha512-c6B0ehIWxMI8wiS/bj6rHMPqeFvngFV7cDU/MY+B16P9Z3Mp9k8L93eYZ7BYzSickzuqAQqAq0V956b3Ju6mLw=="],
+
+ "@sigstore/sign": ["@sigstore/sign@2.3.2", "", { "dependencies": { "@sigstore/bundle": "^2.3.2", "@sigstore/core": "^1.0.0", "@sigstore/protobuf-specs": "^0.3.2", "make-fetch-happen": "^13.0.1", "proc-log": "^4.2.0", "promise-retry": "^2.0.1" } }, "sha512-5Vz5dPVuunIIvC5vBb0APwo7qKA4G9yM48kPWJT+OEERs40md5GoUR1yedwpekWZ4m0Hhw44m6zU+ObsON+iDA=="],
+
+ "@sigstore/tuf": ["@sigstore/tuf@2.3.4", "", { "dependencies": { "@sigstore/protobuf-specs": "^0.3.2", "tuf-js": "^2.2.1" } }, "sha512-44vtsveTPUpqhm9NCrbU8CWLe3Vck2HO1PNLw7RIajbB7xhtn5RBPm1VNSCMwqGYHhDsBJG8gDF0q4lgydsJvw=="],
+
+ "@sigstore/verify": ["@sigstore/verify@1.2.1", "", { "dependencies": { "@sigstore/bundle": "^2.3.2", "@sigstore/core": "^1.1.0", "@sigstore/protobuf-specs": "^0.3.2" } }, "sha512-8iKx79/F73DKbGfRf7+t4dqrc0bRr0thdPrxAtCKWRm/F0tG71i6O1rvlnScncJLLBZHn3h8M3c1BSUAb9yu8g=="],
+
+ "@sindresorhus/is": ["@sindresorhus/is@4.6.0", "", {}, "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw=="],
+
+ "@sindresorhus/merge-streams": ["@sindresorhus/merge-streams@4.0.0", "", {}, "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ=="],
+
+ "@tsconfig/strictest": ["@tsconfig/strictest@2.0.5", "", {}, "sha512-ec4tjL2Rr0pkZ5hww65c+EEPYwxOi4Ryv+0MtjeaSQRJyq322Q27eOQiFbuNgw2hpL4hB1/W/HBGk3VKS43osg=="],
+
+ "@tufjs/canonical-json": ["@tufjs/canonical-json@2.0.0", "", {}, "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA=="],
+
+ "@tufjs/models": ["@tufjs/models@2.0.1", "", { "dependencies": { "@tufjs/canonical-json": "2.0.0", "minimatch": "^9.0.4" } }, "sha512-92F7/SFyufn4DXsha9+QfKnN03JGqtMFMXgSHbZOo8JG59WkTni7UzAouNQDf7AuP9OAMxVOPQcqG3sB7w+kkg=="],
+
+ "@types/bun": ["@types/bun@1.2.8", "", { "dependencies": { "bun-types": "1.2.7" } }, "sha512-t8L1RvJVUghW5V+M/fL3Thbxcs0HwNsXsnTEBEfEVqGteiJToOlZ/fyOEaR1kZsNqnu+3XA4RI/qmnX4w6+S+w=="],
+
+ "@types/conventional-commits-parser": ["@types/conventional-commits-parser@5.0.0", "", { "dependencies": { "@types/node": "*" } }, "sha512-loB369iXNmAZglwWATL+WRe+CRMmmBPtpolYzIebFaX4YA3x+BEfLqhUAV9WanycKI3TG1IMr5bMJDajDKLlUQ=="],
+
+ "@types/node": ["@types/node@20.14.12", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-r7wNXakLeSsGT0H1AU863vS2wa5wBOK4bWMjZz2wj+8nBx+m5PeIn0k8AloSLpRuiwdRQZwarZqHE4FNArPuJQ=="],
+
+ "@types/normalize-package-data": ["@types/normalize-package-data@2.4.4", "", {}, "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA=="],
+
+ "@types/semver": ["@types/semver@7.5.8", "", {}, "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ=="],
+
+ "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="],
+
+ "@vierofernando/decancer-android-arm-eabi": ["@vierofernando/decancer-android-arm-eabi@3.2.8", "", { "os": "android", "cpu": "arm" }, "sha512-MnecYS0LDZUXmSc4fE6C4ecGwzDCI0cmWpGyud6hndpFCxficCZZn0816EQTieAoJzUr2TkQ6iiJnZcTx5nVMA=="],
+
+ "@vierofernando/decancer-android-arm64": ["@vierofernando/decancer-android-arm64@3.2.8", "", { "os": "android", "cpu": "arm64" }, "sha512-rTFNDrvEz6YI3PyGY8lTkCmhOVGopazeMi6LKj0KFRk7b3GkFdTlZNr4+RQMzs+PgB2+jPaWKo2fU0enmPHaRg=="],
+
+ "@vierofernando/decancer-darwin-arm64": ["@vierofernando/decancer-darwin-arm64@3.2.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HTjC+1A9zTukbyL7KASasAcy/0WTtc5BLe9pOT2TuSs+kGgrNWo+YIXZ1/XtcUgrpXwGdWzjp4EQo/vGbQvGHw=="],
+
+ "@vierofernando/decancer-darwin-x64": ["@vierofernando/decancer-darwin-x64@3.2.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-Y2KI9t9AesqoE0PhKG8XaBfCHGw/sNci6fRViK2wjuoVx3gZdBcNKkF1OO/oCDHFaBNi43l9FVPLs1erPQIAow=="],
+
+ "@vierofernando/decancer-freebsd-x64": ["@vierofernando/decancer-freebsd-x64@3.2.8", "", { "os": "freebsd", "cpu": "x64" }, "sha512-L68J4pC/2cNL9MRQpLD5VFiu0zXlfjgwHcXdK/VR9reT8GOWvw7aQnPKFEu7FduJtldoZZt25uGZr2fO+7EWCA=="],
+
+ "@vierofernando/decancer-linux-arm-gnueabihf": ["@vierofernando/decancer-linux-arm-gnueabihf@3.2.8", "", { "os": "linux", "cpu": "arm" }, "sha512-gu40wyOYI+ozm1zCnByA7ooC0zLPEl3+wYra0Px+n+WZI7kErQXNgJmLHqy3QmDZiphlXSJoFcO4rlvd3jpJzQ=="],
+
+ "@vierofernando/decancer-linux-arm64-gnu": ["@vierofernando/decancer-linux-arm64-gnu@3.2.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-FlLSYNo/isdIcJo1pMr2TqehcidRidcMih2xmM4f/c/RengjBljiIfi3OFYPPVTPAhOMn56L88i9PYIqd2jlZA=="],
+
+ "@vierofernando/decancer-linux-arm64-musl": ["@vierofernando/decancer-linux-arm64-musl@3.2.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-A70AAzdRD7CMx8lnRHl4Qst83nsqpzEvNmXbXkbd9FXntao3P+VW7kHcJkWWl51xUYopCZ8geFRgA4SPBQFbUg=="],
+
+ "@vierofernando/decancer-linux-x64-gnu": ["@vierofernando/decancer-linux-x64-gnu@3.2.8", "", { "os": "linux", "cpu": "x64" }, "sha512-kGru28vMBBgz5vpeFKbB3qshfAqgW/RGhjs2GPc73iQ6LX7zLdaD3U8RCKCVPEFDyuN/TpSw1XOckth8sIMdRA=="],
+
+ "@vierofernando/decancer-linux-x64-musl": ["@vierofernando/decancer-linux-x64-musl@3.2.8", "", { "os": "linux", "cpu": "x64" }, "sha512-Aox1+NGM6xduAaInxmfBdc3+0kqjzLdxE3QffNo0QAk6k4ew2NUjdTStvQ/0FHjXe9fmgXDjhrbPLGgh+V/1MQ=="],
+
+ "@vierofernando/decancer-win32-arm64-msvc": ["@vierofernando/decancer-win32-arm64-msvc@3.2.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-buaLM+VaTi3OKEdf6zhg/jZF783CDBbSUapCJYVFxieMCD1RUp0di0jFmVvPfoY/Kj2QfjYuwZJDHXQv3Ds54Q=="],
+
+ "@vierofernando/decancer-win32-ia32-msvc": ["@vierofernando/decancer-win32-ia32-msvc@3.2.8", "", { "os": "win32", "cpu": "ia32" }, "sha512-h3UWbzM3acOXegnEG0GHHC1yEoRpTAyMsOIoGLtsUVr1u/DrEUhOYNBiiQMCa1+9GjZsiEPzIGVoEh5kqPuwSg=="],
+
+ "@vierofernando/decancer-win32-x64-msvc": ["@vierofernando/decancer-win32-x64-msvc@3.2.8", "", { "os": "win32", "cpu": "x64" }, "sha512-zWwNSpt5A69rmjtwx31Nw/KocMNvzFfoi66dK6CtCoLraSpUVXds7BOAGDbaY7eZWdgFBOuePHqy8WMkxrPnoQ=="],
+
+ "@vladfrangu/async_event_emitter": ["@vladfrangu/async_event_emitter@2.4.6", "", {}, "sha512-RaI5qZo6D2CVS6sTHFKg1v5Ohq/+Bo2LZ5gzUEwZ/WkHhwtGTCB/sVLw8ijOkAUxasZ+WshN/Rzj4ywsABJ5ZA=="],
+
+ "JSONStream": ["JSONStream@1.3.5", "", { "dependencies": { "jsonparse": "^1.2.0", "through": ">=2.2.7 <3" }, "bin": { "JSONStream": "./bin.js" } }, "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ=="],
+
+ "abbrev": ["abbrev@2.0.0", "", {}, "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ=="],
+
+ "agent-base": ["agent-base@7.1.1", "", { "dependencies": { "debug": "^4.3.4" } }, "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA=="],
+
+ "aggregate-error": ["aggregate-error@3.1.0", "", { "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" } }, "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA=="],
+
+ "ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
+
+ "ansi-escapes": ["ansi-escapes@7.0.0", "", { "dependencies": { "environment": "^1.0.0" } }, "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw=="],
+
+ "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
+
+ "ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="],
+
+ "any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="],
+
+ "aproba": ["aproba@2.0.0", "", {}, "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ=="],
+
+ "archy": ["archy@1.0.0", "", {}, "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw=="],
+
+ "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
+
+ "argv-formatter": ["argv-formatter@1.0.0", "", {}, "sha512-F2+Hkm9xFaRg+GkaNnbwXNDV5O6pnCFEmqyhvfC/Ic5LbgOWjJh3L+mN/s91rxVL3znE7DYVpW0GJFT+4YBgWw=="],
+
+ "array-ify": ["array-ify@1.0.0", "", {}, "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng=="],
+
+ "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
+
+ "before-after-hook": ["before-after-hook@3.0.2", "", {}, "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A=="],
+
+ "bin-links": ["bin-links@4.0.4", "", { "dependencies": { "cmd-shim": "^6.0.0", "npm-normalize-package-bin": "^3.0.0", "read-cmd-shim": "^4.0.0", "write-file-atomic": "^5.0.0" } }, "sha512-cMtq4W5ZsEwcutJrVId+a/tjt8GSbS+h0oNkdl6+6rBuEv8Ot33Bevj5KPm40t309zuhVic8NjpuL42QCiJWWA=="],
+
+ "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="],
+
+ "blork": ["blork@9.3.0", "", {}, "sha512-9naBrHS2bwCQeGqGR9ptcoll6utsox9jtk1E0SwOAFa4RCV/IQHoBJARdi8AhHQTPPoWkjixMrzHvQKAV5Fx2A=="],
+
+ "bmp-js": ["bmp-js@0.1.0", "", {}, "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw=="],
+
+ "bottleneck": ["bottleneck@2.19.5", "", {}, "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw=="],
+
+ "brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
+
+ "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
+
+ "bson": ["bson@6.10.3", "", {}, "sha512-MTxGsqgYTwfshYWTRdmZRC+M7FnG1b4y7RO7p2k3X24Wq0yv1m77Wsj0BzlPzd/IowgESfsruQCUToa7vbOpPQ=="],
+
+ "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
+
+ "bun-types": ["bun-types@1.2.7", "", { "dependencies": { "@types/node": "*", "@types/ws": "*" } }, "sha512-P4hHhk7kjF99acXqKvltyuMQ2kf/rzIw3ylEDpCxDS9Xa0X0Yp/gJu/vDCucmWpiur5qJ0lwB2bWzOXa2GlHqA=="],
+
+ "cacache": ["cacache@18.0.4", "", { "dependencies": { "@npmcli/fs": "^3.1.0", "fs-minipass": "^3.0.0", "glob": "^10.2.2", "lru-cache": "^10.0.1", "minipass": "^7.0.3", "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "p-map": "^4.0.0", "ssri": "^10.0.0", "tar": "^6.1.11", "unique-filename": "^3.0.0" } }, "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ=="],
+
+ "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
+
+ "chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="],
+
+ "char-regex": ["char-regex@1.0.2", "", {}, "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw=="],
+
+ "chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="],
+
+ "ci-info": ["ci-info@4.0.0", "", {}, "sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg=="],
+
+ "cidr-regex": ["cidr-regex@4.1.1", "", { "dependencies": { "ip-regex": "^5.0.0" } }, "sha512-ekKcVp+iRB9zlKFXyx7io7nINgb0oRjgRdXNEodp1OuxRui8FXr/CA40Tz1voWUp9DPPrMyQKy01vJhDo4N1lw=="],
+
+ "clean-stack": ["clean-stack@2.2.0", "", {}, "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A=="],
+
+ "cli-columns": ["cli-columns@4.0.0", "", { "dependencies": { "string-width": "^4.2.3", "strip-ansi": "^6.0.1" } }, "sha512-XW2Vg+w+L9on9wtwKpyzluIPCWXjaBahI7mTcYjx+BVIYD9c3yqcv/yKC7CmdCZat4rq2yiE1UMSJC5ivKfMtQ=="],
+
+ "cli-highlight": ["cli-highlight@2.1.11", "", { "dependencies": { "chalk": "^4.0.0", "highlight.js": "^10.7.1", "mz": "^2.4.0", "parse5": "^5.1.1", "parse5-htmlparser2-tree-adapter": "^6.0.0", "yargs": "^16.0.0" }, "bin": { "highlight": "bin/highlight" } }, "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg=="],
+
+ "cli-table3": ["cli-table3@0.6.5", "", { "dependencies": { "string-width": "^4.2.0" }, "optionalDependencies": { "@colors/colors": "1.5.0" } }, "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ=="],
+
+ "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
+
+ "cmd-shim": ["cmd-shim@6.0.3", "", {}, "sha512-FMabTRlc5t5zjdenF6mS0MBeFZm0XqHqeOkcskKFb/LYCcRQ5fVgLOHVc4Lq9CqABd9zhjwPjMBCJvMCziSVtA=="],
+
+ "color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="],
+
+ "color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="],
+
+ "colors": ["colors@1.4.0", "", {}, "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA=="],
+
+ "common-ancestor-path": ["common-ancestor-path@1.0.1", "", {}, "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w=="],
+
+ "compare-func": ["compare-func@2.0.0", "", { "dependencies": { "array-ify": "^1.0.0", "dot-prop": "^5.1.0" } }, "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA=="],
+
+ "config-chain": ["config-chain@1.1.13", "", { "dependencies": { "ini": "^1.3.4", "proto-list": "~1.2.1" } }, "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ=="],
+
+ "conventional-changelog-angular": ["conventional-changelog-angular@8.0.0", "", { "dependencies": { "compare-func": "^2.0.0" } }, "sha512-CLf+zr6St0wIxos4bmaKHRXWAcsCXrJU6F4VdNDrGRK3B8LDLKoX3zuMV5GhtbGkVR/LohZ6MT6im43vZLSjmA=="],
+
+ "conventional-changelog-conventionalcommits": ["conventional-changelog-conventionalcommits@7.0.2", "", { "dependencies": { "compare-func": "^2.0.0" } }, "sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w=="],
+
+ "conventional-changelog-writer": ["conventional-changelog-writer@8.0.0", "", { "dependencies": { "@types/semver": "^7.5.5", "conventional-commits-filter": "^5.0.0", "handlebars": "^4.7.7", "meow": "^13.0.0", "semver": "^7.5.2" }, "bin": { "conventional-changelog-writer": "dist/cli/index.js" } }, "sha512-TQcoYGRatlAnT2qEWDON/XSfnVG38JzA7E0wcGScu7RElQBkg9WWgZd1peCWFcWDh1xfb2CfsrcvOn1bbSzztA=="],
+
+ "conventional-commits-filter": ["conventional-commits-filter@5.0.0", "", {}, "sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q=="],
+
+ "conventional-commits-parser": ["conventional-commits-parser@6.0.0", "", { "dependencies": { "meow": "^13.0.0" }, "bin": { "conventional-commits-parser": "dist/cli/index.js" } }, "sha512-TbsINLp48XeMXR8EvGjTnKGsZqBemisPoyWESlpRyR8lif0lcwzqz+NMtYSj1ooF/WYjSuu7wX0CtdeeMEQAmA=="],
+
+ "convert-hrtime": ["convert-hrtime@5.0.0", "", {}, "sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg=="],
+
+ "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="],
+
+ "cosmiconfig": ["cosmiconfig@9.0.0", "", { "dependencies": { "env-paths": "^2.2.1", "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", "parse-json": "^5.2.0" }, "peerDependencies": { "typescript": ">=4.9.5" }, "optionalPeers": ["typescript"] }, "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg=="],
+
+ "cosmiconfig-typescript-loader": ["cosmiconfig-typescript-loader@6.1.0", "", { "dependencies": { "jiti": "^2.4.1" }, "peerDependencies": { "@types/node": "*", "cosmiconfig": ">=9", "typescript": ">=5" } }, "sha512-tJ1w35ZRUiM5FeTzT7DtYWAFFv37ZLqSRkGi2oeCK1gPhvaWjkAtfXvLmvE1pRfxxp9aQo6ba/Pvg1dKj05D4g=="],
+
+ "cross-spawn": ["cross-spawn@7.0.3", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w=="],
+
+ "crypto-random-string": ["crypto-random-string@4.0.0", "", { "dependencies": { "type-fest": "^1.0.1" } }, "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA=="],
+
+ "cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="],
+
+ "dargs": ["dargs@8.1.0", "", {}, "sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw=="],
+
+ "data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="],
+
+ "dateformat": ["dateformat@4.5.1", "", {}, "sha512-OD0TZ+B7yP7ZgpJf5K2DIbj3FZvFvxgFUuaqA/V5zTjAtAAXZ1E8bktHxmAGs4x5b7PflqA9LeQ84Og7wYtF7Q=="],
+
+ "debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+
+ "decancer": ["decancer@3.2.8", "", { "optionalDependencies": { "@vierofernando/decancer-android-arm-eabi": "3.2.8", "@vierofernando/decancer-android-arm64": "3.2.8", "@vierofernando/decancer-darwin-arm64": "3.2.8", "@vierofernando/decancer-darwin-x64": "3.2.8", "@vierofernando/decancer-freebsd-x64": "3.2.8", "@vierofernando/decancer-linux-arm-gnueabihf": "3.2.8", "@vierofernando/decancer-linux-arm64-gnu": "3.2.8", "@vierofernando/decancer-linux-arm64-musl": "3.2.8", "@vierofernando/decancer-linux-x64-gnu": "3.2.8", "@vierofernando/decancer-linux-x64-musl": "3.2.8", "@vierofernando/decancer-win32-arm64-msvc": "3.2.8", "@vierofernando/decancer-win32-ia32-msvc": "3.2.8", "@vierofernando/decancer-win32-x64-msvc": "3.2.8" } }, "sha512-KGz0d/6gV0aPqaDb11ZPV38kBdqQ8198Mo2ZY8lW59XGq9o6uRIy+k3AIqmj9vZLKDniP7uVXstj0IBOYkzM6w=="],
+
+ "deep-extend": ["deep-extend@0.6.0", "", {}, "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="],
+
+ "deprecation": ["deprecation@2.3.1", "", {}, "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="],
+
+ "detect-indent": ["detect-indent@7.0.1", "", {}, "sha512-Mc7QhQ8s+cLrnUfU/Ji94vG/r8M26m8f++vyres4ZoojaRDpZ1eSIh/EpzLNwlWuvzSZ3UbDFspjFvTDXe6e/g=="],
+
+ "detect-libc": ["detect-libc@2.0.2", "", {}, "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw=="],
+
+ "detect-newline": ["detect-newline@4.0.1", "", {}, "sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog=="],
+
+ "diff": ["diff@5.2.0", "", {}, "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A=="],
+
+ "dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "^4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="],
+
+ "discord-api-types": ["discord-api-types@0.37.119", "", {}, "sha512-WasbGFXEB+VQWXlo6IpW3oUv73Yuau1Ig4AZF/m13tXcTKnMpc/mHjpztIlz4+BM9FG9BHQkEXiPto3bKduQUg=="],
+
+ "discord.js": ["discord.js@14.18.0", "", { "dependencies": { "@discordjs/builders": "^1.10.1", "@discordjs/collection": "1.5.3", "@discordjs/formatters": "^0.6.0", "@discordjs/rest": "^2.4.3", "@discordjs/util": "^1.1.1", "@discordjs/ws": "^1.2.1", "@sapphire/snowflake": "3.5.3", "discord-api-types": "^0.37.119", "fast-deep-equal": "3.1.3", "lodash.snakecase": "4.1.1", "tslib": "^2.6.3", "undici": "6.21.1" } }, "sha512-SvU5kVUvwunQhN2/+0t55QW/1EHfB1lp0TtLZUSXVHDmyHTrdOj5LRKdR0zLcybaA15F+NtdWuWmGOX9lE+CAw=="],
+
+ "dot-prop": ["dot-prop@5.3.0", "", { "dependencies": { "is-obj": "^2.0.0" } }, "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q=="],
+
+ "drizzle-kit": ["drizzle-kit@0.22.8", "", { "dependencies": { "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.19.7", "esbuild-register": "^3.5.0" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-VjI4wsJjk3hSqHSa3TwBf+uvH6M6pRHyxyoVbt935GUzP9tUR/BRZ+MhEJNgryqbzN2Za1KP0eJMTgKEPsalYQ=="],
+
+ "drizzle-orm": ["drizzle-orm@0.31.4", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=3", "@electric-sql/pglite": ">=0.1.1", "@libsql/client": "*", "@neondatabase/serverless": ">=0.1", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/react": ">=18", "@types/sql.js": "*", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=13.2.0", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "react": ">=18", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/react", "@types/sql.js", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "knex", "kysely", "mysql2", "pg", "postgres", "react", "sql.js", "sqlite3"] }, "sha512-VGD9SH9aStF2z4QOTnVlVX/WghV/EnuEzTmsH3fSVp2E4fFgc8jl3viQrS/XUJx1ekW4rVVLJMH42SfGQdjX3Q=="],
+
+ "duplexer2": ["duplexer2@0.1.4", "", { "dependencies": { "readable-stream": "^2.0.2" } }, "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA=="],
+
+ "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
+
+ "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
+
+ "emojilib": ["emojilib@2.4.0", "", {}, "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw=="],
+
+ "encoding": ["encoding@0.1.13", "", { "dependencies": { "iconv-lite": "^0.6.2" } }, "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A=="],
+
+ "end-of-stream": ["end-of-stream@1.4.4", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q=="],
+
+ "env-ci": ["env-ci@11.0.0", "", { "dependencies": { "execa": "^8.0.0", "java-properties": "^1.0.2" } }, "sha512-apikxMgkipkgTvMdRT9MNqWx5VLOci79F4VBd7Op/7OPjjoanjdAvn6fglMCCEf/1bAh8eOiuEVCUs4V3qP3nQ=="],
+
+ "env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="],
+
+ "environment": ["environment@1.1.0", "", {}, "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q=="],
+
+ "err-code": ["err-code@2.0.3", "", {}, "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA=="],
+
+ "error-ex": ["error-ex@1.3.2", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g=="],
+
+ "esbuild": ["esbuild@0.19.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.19.12", "@esbuild/android-arm": "0.19.12", "@esbuild/android-arm64": "0.19.12", "@esbuild/android-x64": "0.19.12", "@esbuild/darwin-arm64": "0.19.12", "@esbuild/darwin-x64": "0.19.12", "@esbuild/freebsd-arm64": "0.19.12", "@esbuild/freebsd-x64": "0.19.12", "@esbuild/linux-arm": "0.19.12", "@esbuild/linux-arm64": "0.19.12", "@esbuild/linux-ia32": "0.19.12", "@esbuild/linux-loong64": "0.19.12", "@esbuild/linux-mips64el": "0.19.12", "@esbuild/linux-ppc64": "0.19.12", "@esbuild/linux-riscv64": "0.19.12", "@esbuild/linux-s390x": "0.19.12", "@esbuild/linux-x64": "0.19.12", "@esbuild/netbsd-x64": "0.19.12", "@esbuild/openbsd-x64": "0.19.12", "@esbuild/sunos-x64": "0.19.12", "@esbuild/win32-arm64": "0.19.12", "@esbuild/win32-ia32": "0.19.12", "@esbuild/win32-x64": "0.19.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg=="],
+
+ "esbuild-register": ["esbuild-register@3.6.0", "", { "dependencies": { "debug": "^4.3.4" }, "peerDependencies": { "esbuild": ">=0.12 <1" } }, "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg=="],
+
+ "escalade": ["escalade@3.1.2", "", {}, "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA=="],
+
+ "escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="],
+
+ "execa": ["execa@9.5.2", "", { "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "cross-spawn": "^7.0.3", "figures": "^6.1.0", "get-stream": "^9.0.0", "human-signals": "^8.0.0", "is-plain-obj": "^4.1.0", "is-stream": "^4.0.1", "npm-run-path": "^6.0.0", "pretty-ms": "^9.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^4.0.0", "yoctocolors": "^2.0.0" } }, "sha512-EHlpxMCpHWSAh1dgS6bVeoLAXGnJNdR93aabr4QCGbzOM73o5XmRfM/e5FUqsw3aagP8S8XEWUWFAxnRBnAF0Q=="],
+
+ "exponential-backoff": ["exponential-backoff@3.1.1", "", {}, "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw=="],
+
+ "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
+
+ "fast-glob": ["fast-glob@3.3.2", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow=="],
+
+ "fast-uri": ["fast-uri@3.0.1", "", {}, "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw=="],
+
+ "fastest-levenshtein": ["fastest-levenshtein@1.0.16", "", {}, "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg=="],
+
+ "fastq": ["fastq@1.17.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w=="],
+
+ "fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="],
+
+ "figures": ["figures@6.1.0", "", { "dependencies": { "is-unicode-supported": "^2.0.0" } }, "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg=="],
+
+ "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
+
+ "find-up": ["find-up@2.1.0", "", { "dependencies": { "locate-path": "^2.0.0" } }, "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ=="],
+
+ "find-up-simple": ["find-up-simple@1.0.0", "", {}, "sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw=="],
+
+ "find-versions": ["find-versions@6.0.0", "", { "dependencies": { "semver-regex": "^4.0.5", "super-regex": "^1.0.0" } }, "sha512-2kCCtc+JvcZ86IGAz3Z2Y0A1baIz9fL31pH/0S1IqZr9Iwnjq8izfPtrCyQKO6TLMPELLsQMre7VDqeIKCsHkA=="],
+
+ "foreground-child": ["foreground-child@3.2.1", "", { "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" } }, "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA=="],
+
+ "formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="],
+
+ "from2": ["from2@2.3.0", "", { "dependencies": { "inherits": "^2.0.1", "readable-stream": "^2.0.0" } }, "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g=="],
+
+ "fs-extra": ["fs-extra@11.2.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw=="],
+
+ "fs-minipass": ["fs-minipass@3.0.3", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw=="],
+
+ "function-timeout": ["function-timeout@1.0.2", "", {}, "sha512-939eZS4gJ3htTHAldmyyuzlrD58P03fHG49v2JfFXbV6OhvZKRC9j2yAtdHw/zrp2zXHuv05zMIy40F0ge7spA=="],
+
+ "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
+
+ "get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="],
+
+ "get-tsconfig": ["get-tsconfig@4.7.6", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA=="],
+
+ "git-log-parser": ["git-log-parser@1.2.1", "", { "dependencies": { "argv-formatter": "~1.0.0", "spawn-error-forwarder": "~1.0.0", "split2": "~1.0.0", "stream-combiner2": "~1.1.1", "through2": "~2.0.0", "traverse": "0.6.8" } }, "sha512-PI+sPDvHXNPl5WNOErAK05s3j0lgwUzMN6o8cyQrDaKfT3qd7TmNJKeXX+SknI5I0QhG5fVPAEwSY4tRGDtYoQ=="],
+
+ "git-raw-commits": ["git-raw-commits@4.0.0", "", { "dependencies": { "dargs": "^8.0.0", "meow": "^12.0.1", "split2": "^4.0.0" }, "bin": { "git-raw-commits": "cli.mjs" } }, "sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ=="],
+
+ "glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="],
+
+ "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
+
+ "global-directory": ["global-directory@4.0.1", "", { "dependencies": { "ini": "4.1.1" } }, "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q=="],
+
+ "globby": ["globby@14.0.2", "", { "dependencies": { "@sindresorhus/merge-streams": "^2.1.0", "fast-glob": "^3.3.2", "ignore": "^5.2.4", "path-type": "^5.0.0", "slash": "^5.1.0", "unicorn-magic": "^0.1.0" } }, "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw=="],
+
+ "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
+
+ "handlebars": ["handlebars@4.7.8", "", { "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, "optionalDependencies": { "uglify-js": "^3.1.4" }, "bin": { "handlebars": "bin/handlebars" } }, "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ=="],
+
+ "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
+
+ "highlight.js": ["highlight.js@10.7.3", "", {}, "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A=="],
+
+ "hook-std": ["hook-std@3.0.0", "", {}, "sha512-jHRQzjSDzMtFy34AGj1DN+vq54WVuhSvKgrHf0OMiFQTwDD4L/qqofVEWjLOBMTn5+lCD3fPg32W9yOfnEJTTw=="],
+
+ "hosted-git-info": ["hosted-git-info@8.0.0", "", { "dependencies": { "lru-cache": "^10.0.1" } }, "sha512-4nw3vOVR+vHUOT8+U4giwe2tcGv+R3pwwRidUe67DoMBTjhrfr6rZYJVVwdkBE+Um050SG+X9tf0Jo4fOpn01w=="],
+
+ "http-cache-semantics": ["http-cache-semantics@4.1.1", "", {}, "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ=="],
+
+ "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="],
+
+ "https-proxy-agent": ["https-proxy-agent@7.0.5", "", { "dependencies": { "agent-base": "^7.0.2", "debug": "4" } }, "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw=="],
+
+ "human-signals": ["human-signals@8.0.0", "", {}, "sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA=="],
+
+ "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
+
+ "idb-keyval": ["idb-keyval@6.2.1", "", {}, "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg=="],
+
+ "ignore": ["ignore@5.3.1", "", {}, "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw=="],
+
+ "ignore-walk": ["ignore-walk@6.0.5", "", { "dependencies": { "minimatch": "^9.0.0" } }, "sha512-VuuG0wCnjhnylG1ABXT3dAuIpTNDs/G8jlpmwXY03fXoXy/8ZK8/T+hMzt8L4WnrLCJgdybqgPagnF/f97cg3A=="],
+
+ "import-fresh": ["import-fresh@3.3.0", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw=="],
+
+ "import-from-esm": ["import-from-esm@2.0.0", "", { "dependencies": { "debug": "^4.3.4", "import-meta-resolve": "^4.0.0" } }, "sha512-YVt14UZCgsX1vZQ3gKjkWVdBdHQ6eu3MPU1TBgL1H5orXe2+jWD006WCPPtOuwlQm10NuzOW5WawiF1Q9veW8g=="],
+
+ "import-meta-resolve": ["import-meta-resolve@4.1.0", "", {}, "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw=="],
+
+ "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
+
+ "indent-string": ["indent-string@4.0.0", "", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="],
+
+ "index-to-position": ["index-to-position@0.1.2", "", {}, "sha512-MWDKS3AS1bGCHLBA2VLImJz42f7bJh8wQsTGCzI3j519/CASStoDONUBVz2I/VID0MpiX3SGSnbOD2xUalbE5g=="],
+
+ "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
+
+ "ini": ["ini@4.1.3", "", {}, "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg=="],
+
+ "init-package-json": ["init-package-json@6.0.3", "", { "dependencies": { "@npmcli/package-json": "^5.0.0", "npm-package-arg": "^11.0.0", "promzard": "^1.0.0", "read": "^3.0.1", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4", "validate-npm-package-name": "^5.0.0" } }, "sha512-Zfeb5ol+H+eqJWHTaGca9BovufyGeIfr4zaaBorPmJBMrJ+KBnN+kQx2ZtXdsotUTgldHmHQV44xvUWOUA7E2w=="],
+
+ "into-stream": ["into-stream@7.0.0", "", { "dependencies": { "from2": "^2.3.0", "p-is-promise": "^3.0.0" } }, "sha512-2dYz766i9HprMBasCMvHMuazJ7u4WzhJwo5kb3iPSiW/iRYV6uPari3zHoqZlnuaR7V1bEiNMxikhp37rdBXbw=="],
+
+ "ip-address": ["ip-address@9.0.5", "", { "dependencies": { "jsbn": "1.1.0", "sprintf-js": "^1.1.3" } }, "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g=="],
+
+ "ip-regex": ["ip-regex@5.0.0", "", {}, "sha512-fOCG6lhoKKakwv+C6KdsOnGvgXnmgfmp0myi3bcNwj3qfwPAxRKWEuFhvEFF7ceYIz6+1jRZ+yguLFAmUNPEfw=="],
+
+ "is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="],
+
+ "is-cidr": ["is-cidr@5.1.0", "", { "dependencies": { "cidr-regex": "^4.1.1" } }, "sha512-OkVS+Ht2ssF27d48gZdB+ho1yND1VbkJRKKS6Pc1/Cw7uqkd9IOJg8/bTwBDQL6tfBhSdguPRnlGiE8pU/X5NQ=="],
+
+ "is-electron": ["is-electron@2.2.2", "", {}, "sha512-FO/Rhvz5tuw4MCWkpMzHFKWD2LsfHzIb7i6MdPYZ/KW7AlxawyLkqdy+jPZP1WubqEADE3O4FUENlJHDfQASRg=="],
+
+ "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
+
+ "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
+
+ "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
+
+ "is-lambda": ["is-lambda@1.0.1", "", {}, "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ=="],
+
+ "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
+
+ "is-obj": ["is-obj@2.0.0", "", {}, "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="],
+
+ "is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="],
+
+ "is-stream": ["is-stream@4.0.1", "", {}, "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A=="],
+
+ "is-text-path": ["is-text-path@2.0.0", "", { "dependencies": { "text-extensions": "^2.0.0" } }, "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw=="],
+
+ "is-unicode-supported": ["is-unicode-supported@2.0.0", "", {}, "sha512-FRdAyx5lusK1iHG0TWpVtk9+1i+GjrzRffhDg4ovQ7mcidMQ6mj+MhKPmvh7Xwyv5gIS06ns49CA7Sqg7lC22Q=="],
+
+ "is-url": ["is-url@1.2.4", "", {}, "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww=="],
+
+ "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="],
+
+ "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
+
+ "issue-parser": ["issue-parser@7.0.1", "", { "dependencies": { "lodash.capitalize": "^4.2.1", "lodash.escaperegexp": "^4.1.2", "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.uniqby": "^4.7.0" } }, "sha512-3YZcUUR2Wt1WsapF+S/WiA2WmlW0cWAoPccMqne7AxEBhCdFeTPjfv/Axb8V2gyCgY3nRw+ksZ3xSUX+R47iAg=="],
+
+ "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="],
+
+ "java-properties": ["java-properties@1.0.2", "", {}, "sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ=="],
+
+ "jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="],
+
+ "js-base64": ["js-base64@3.7.7", "", {}, "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw=="],
+
+ "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
+
+ "js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="],
+
+ "jsbn": ["jsbn@1.1.0", "", {}, "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A=="],
+
+ "json-parse-better-errors": ["json-parse-better-errors@1.0.2", "", {}, "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="],
+
+ "json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "", {}, "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="],
+
+ "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
+
+ "json-stringify-nice": ["json-stringify-nice@1.1.4", "", {}, "sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw=="],
+
+ "json-stringify-safe": ["json-stringify-safe@5.0.1", "", {}, "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="],
+
+ "jsonfile": ["jsonfile@6.1.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ=="],
+
+ "jsonparse": ["jsonparse@1.3.1", "", {}, "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg=="],
+
+ "just-diff": ["just-diff@6.0.2", "", {}, "sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA=="],
+
+ "just-diff-apply": ["just-diff-apply@5.5.0", "", {}, "sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw=="],
+
+ "lefthook": ["lefthook@1.11.6", "", { "optionalDependencies": { "lefthook-darwin-arm64": "1.11.6", "lefthook-darwin-x64": "1.11.6", "lefthook-freebsd-arm64": "1.11.6", "lefthook-freebsd-x64": "1.11.6", "lefthook-linux-arm64": "1.11.6", "lefthook-linux-x64": "1.11.6", "lefthook-openbsd-arm64": "1.11.6", "lefthook-openbsd-x64": "1.11.6", "lefthook-windows-arm64": "1.11.6", "lefthook-windows-x64": "1.11.6" }, "bin": { "lefthook": "bin/index.js" } }, "sha512-j0VmMM50WlPDassmgvapRum9po29Tv1BXzBNFpzGkk9E91CEG9jKik/OHyH/r/na+q8qNIUUyPL6QQuTN/UhQQ=="],
+
+ "lefthook-darwin-arm64": ["lefthook-darwin-arm64@1.11.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gWgdWrKgZgX+bKc6Vs/x7JkO+58lLOpRzpteLx//82D0MKVPlNZwjd4zz4AbIBXtM4Hcj+6gSsOzQ7QDXxjVvQ=="],
+
+ "lefthook-darwin-x64": ["lefthook-darwin-x64@1.11.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-Ia0TjTKuYcSaDTuoCnbWtpPZ2VEoKzgn33OB90VjNaSVs4ooE0PIdpO+w00x1elqIaf1pbrpq6HgeB26Du8KbQ=="],
+
+ "lefthook-freebsd-arm64": ["lefthook-freebsd-arm64@1.11.6", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-PxIwj+hmjLahyzEmcIfalIBDhgklAQCavwM4sGCgbzDi4/+VQX+4aEs4pQqtd7v3aohmjtO/4n2emzTI8donww=="],
+
+ "lefthook-freebsd-x64": ["lefthook-freebsd-x64@1.11.6", "", { "os": "freebsd", "cpu": "x64" }, "sha512-3o1lMKxz1VtWaP/o117wgUn3ZOpefMoSf+8LuiTzI3/PDprIuzgyw2nXKlBZAMDpNPHMNnJeQNts9XLMRmkldg=="],
+
+ "lefthook-linux-arm64": ["lefthook-linux-arm64@1.11.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-nKPFZ5cA9f5tVn0ybDVqcXXlpTHZqo05N4KQRhWTj5Nem+JoD2YzJIlvZhdJhUrldERqj6deDMXChH5T3z4Rrw=="],
+
+ "lefthook-linux-x64": ["lefthook-linux-x64@1.11.6", "", { "os": "linux", "cpu": "x64" }, "sha512-naN8dllLCOEeP+wznLnq+oXrs1dvt/iMLkcl+pOPWLqFccPfDiHzr8V8GslaTa+rSFsAnvjR7SJIOi5C29xedA=="],
+
+ "lefthook-openbsd-arm64": ["lefthook-openbsd-arm64@1.11.6", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-dPxhJfYQ667T+U3pz1+O3mTRNHzXH/BvPlXSH+oy8uiSry4AtVNRXkVvXPUcpLlrAy6HuFYodsrpCIlWFeYwiQ=="],
+
+ "lefthook-openbsd-x64": ["lefthook-openbsd-x64@1.11.6", "", { "os": "openbsd", "cpu": "x64" }, "sha512-9D26kcSsjiW4D0AuVDdi+0ZqrsOzRWOpMS/kcUbLfrU99yCvma0rMTqKbbDMkVur/znS7qL53oGahXCXDNA+IQ=="],
+
+ "lefthook-windows-arm64": ["lefthook-windows-arm64@1.11.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-xdCenr4+BFnfBEhiXj6GJp02EPmcwTAGa7NYm6hVTfDwGXw24tuLv7lpnGjgK3kovN6EukgLH1FYkeyDOBEMnA=="],
+
+ "lefthook-windows-x64": ["lefthook-windows-x64@1.11.6", "", { "os": "win32", "cpu": "x64" }, "sha512-Fg2GzLhzeDV/GX8+ydrI0wBOytQWpPkNdngx+a8B/feCDbwjAiFklDG5oV4ytuWrtg1JPEEWLJd6nHefj4wtHA=="],
+
+ "libnpmaccess": ["libnpmaccess@8.0.6", "", { "dependencies": { "npm-package-arg": "^11.0.2", "npm-registry-fetch": "^17.0.1" } }, "sha512-uM8DHDEfYG6G5gVivVl+yQd4pH3uRclHC59lzIbSvy7b5FEwR+mU49Zq1jEyRtRFv7+M99mUW9S0wL/4laT4lw=="],
+
+ "libnpmdiff": ["libnpmdiff@6.1.4", "", { "dependencies": { "@npmcli/arborist": "^7.5.4", "@npmcli/installed-package-contents": "^2.1.0", "binary-extensions": "^2.3.0", "diff": "^5.1.0", "minimatch": "^9.0.4", "npm-package-arg": "^11.0.2", "pacote": "^18.0.6", "tar": "^6.2.1" } }, "sha512-KCNoCY8kjQ16/EE4VoW7AYqecsb9frNIh/cPwWQSk1s2grzZMQH+Scp7Yo7Fk6SWTkyVDLZEYfUT/vKONYrfmg=="],
+
+ "libnpmexec": ["libnpmexec@8.1.3", "", { "dependencies": { "@npmcli/arborist": "^7.5.4", "@npmcli/run-script": "^8.1.0", "ci-info": "^4.0.0", "npm-package-arg": "^11.0.2", "pacote": "^18.0.6", "proc-log": "^4.2.0", "read": "^3.0.1", "read-package-json-fast": "^3.0.2", "semver": "^7.3.7", "walk-up-path": "^3.0.1" } }, "sha512-DOI1G8R1mEVOGkXdQ73KXUTm3NuPjcfb7UazqVVjpl/xtosuK5p5a68TO6Nt6UWjOOiizTudAw8hI7psw5/t6w=="],
+
+ "libnpmfund": ["libnpmfund@5.0.12", "", { "dependencies": { "@npmcli/arborist": "^7.5.4" } }, "sha512-lox1UHcv8/r/TE+T9B+aOylU3c13tK2IuwwUwUm+YMw+C/iq14dqskHqhGPTqa75ZJbiVOW7PMWO92Wn5HG49Q=="],
+
+ "libnpmhook": ["libnpmhook@10.0.5", "", { "dependencies": { "aproba": "^2.0.0", "npm-registry-fetch": "^17.0.1" } }, "sha512-XulT+N/s3o9oFlIq6pGRv3OG2qR1NVRbVQOKLchycDwyf16RZA3oXbeEgs2H3oE7hRZPUMBZqsalQXMMPal3cQ=="],
+
+ "libnpmorg": ["libnpmorg@6.0.6", "", { "dependencies": { "aproba": "^2.0.0", "npm-registry-fetch": "^17.0.1" } }, "sha512-4MVxsAS4H2z7su/sU0GsrirfBm4ssfqPRSDvoZ8qmRw58kEWJ0qE0cQ2VilRlFgCWKzKPhfoPeyNPyxBTnOusA=="],
+
+ "libnpmpack": ["libnpmpack@7.0.4", "", { "dependencies": { "@npmcli/arborist": "^7.5.4", "@npmcli/run-script": "^8.1.0", "npm-package-arg": "^11.0.2", "pacote": "^18.0.6" } }, "sha512-oKZA0afbueiC88lskXzAEr3DCN9BTMbUySjUce6qhBV9CjYF2R/x347KhgHu75+p9W2Rd57ZvKz81c5a2+9h6Q=="],
+
+ "libnpmpublish": ["libnpmpublish@9.0.9", "", { "dependencies": { "ci-info": "^4.0.0", "normalize-package-data": "^6.0.1", "npm-package-arg": "^11.0.2", "npm-registry-fetch": "^17.0.1", "proc-log": "^4.2.0", "semver": "^7.3.7", "sigstore": "^2.2.0", "ssri": "^10.0.6" } }, "sha512-26zzwoBNAvX9AWOPiqqF6FG4HrSCPsHFkQm7nT+xU1ggAujL/eae81RnCv4CJ2In9q9fh10B88sYSzKCUh/Ghg=="],
+
+ "libnpmsearch": ["libnpmsearch@7.0.6", "", { "dependencies": { "npm-registry-fetch": "^17.0.1" } }, "sha512-PmiER4bgiIqN9OjBtgPn2/PxwU+OdJWtLBFM+vewOrn4VmaNAHSUKDt/wxOOkZSDLyMICVUBp61Ji1+XxhSrKw=="],
+
+ "libnpmteam": ["libnpmteam@6.0.5", "", { "dependencies": { "aproba": "^2.0.0", "npm-registry-fetch": "^17.0.1" } }, "sha512-iJW4Cq42GMqMwZEV+Mx8ZLj0Np5kGXQ9P/BAekHjIpYC1v3/vJqbmfJkzkwFvGxEhUotmx+xpLChZCDJ7c3rxA=="],
+
+ "libnpmversion": ["libnpmversion@6.0.3", "", { "dependencies": { "@npmcli/git": "^5.0.7", "@npmcli/run-script": "^8.1.0", "json-parse-even-better-errors": "^3.0.2", "proc-log": "^4.2.0", "semver": "^7.3.7" } }, "sha512-Kjk1anQ9sPn7E/qF1jXumItvr2OA1914tYWkSTXH9G2rYoY+Ol1+KNrWfGeje2aBvFfKlt4VeKdCfM3yxMXNBw=="],
+
+ "libsql": ["libsql@0.3.19", "", { "dependencies": { "@neon-rs/load": "^0.0.4", "detect-libc": "2.0.2", "libsql": "^0.3.15" }, "optionalDependencies": { "@libsql/darwin-arm64": "0.3.19", "@libsql/darwin-x64": "0.3.19", "@libsql/linux-arm64-gnu": "0.3.19", "@libsql/linux-arm64-musl": "0.3.19", "@libsql/linux-x64-gnu": "0.3.19", "@libsql/linux-x64-musl": "0.3.19", "@libsql/win32-x64-msvc": "0.3.19" }, "os": [ "linux", "win32", "darwin", ], "cpu": [ "x64", "arm64", ] }, "sha512-Aj5cQ5uk/6fHdmeW0TiXK42FqUlwx7ytmMLPSaUQPin5HKKKuUPD62MAbN4OEweGBBI7q1BekoEN4gPUEL6MZA=="],
+
+ "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="],
+
+ "load-json-file": ["load-json-file@4.0.0", "", { "dependencies": { "graceful-fs": "^4.1.2", "parse-json": "^4.0.0", "pify": "^3.0.0", "strip-bom": "^3.0.0" } }, "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw=="],
+
+ "locate-path": ["locate-path@2.0.0", "", { "dependencies": { "p-locate": "^2.0.0", "path-exists": "^3.0.0" } }, "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA=="],
+
+ "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
+
+ "lodash-es": ["lodash-es@4.17.21", "", {}, "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="],
+
+ "lodash.camelcase": ["lodash.camelcase@4.3.0", "", {}, "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="],
+
+ "lodash.capitalize": ["lodash.capitalize@4.2.1", "", {}, "sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw=="],
+
+ "lodash.escaperegexp": ["lodash.escaperegexp@4.1.2", "", {}, "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw=="],
+
+ "lodash.isplainobject": ["lodash.isplainobject@4.0.6", "", {}, "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="],
+
+ "lodash.isstring": ["lodash.isstring@4.0.1", "", {}, "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw=="],
+
+ "lodash.kebabcase": ["lodash.kebabcase@4.1.1", "", {}, "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g=="],
+
+ "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="],
+
+ "lodash.mergewith": ["lodash.mergewith@4.6.2", "", {}, "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ=="],
+
+ "lodash.snakecase": ["lodash.snakecase@4.1.1", "", {}, "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw=="],
+
+ "lodash.startcase": ["lodash.startcase@4.4.0", "", {}, "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg=="],
+
+ "lodash.uniq": ["lodash.uniq@4.5.0", "", {}, "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ=="],
+
+ "lodash.uniqby": ["lodash.uniqby@4.7.0", "", {}, "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww=="],
+
+ "lodash.upperfirst": ["lodash.upperfirst@4.3.1", "", {}, "sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg=="],
+
+ "lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
+
+ "magic-bytes.js": ["magic-bytes.js@1.10.0", "", {}, "sha512-/k20Lg2q8LE5xiaaSkMXk4sfvI+9EGEykFS4b0CHHGWqDYU0bGUFSwchNOMA56D7TCs9GwVTkqe9als1/ns8UQ=="],
+
+ "make-fetch-happen": ["make-fetch-happen@13.0.1", "", { "dependencies": { "@npmcli/agent": "^2.0.0", "cacache": "^18.0.0", "http-cache-semantics": "^4.1.1", "is-lambda": "^1.0.1", "minipass": "^7.0.2", "minipass-fetch": "^3.0.0", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^0.6.3", "proc-log": "^4.2.0", "promise-retry": "^2.0.1", "ssri": "^10.0.0" } }, "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA=="],
+
+ "marked": ["marked@12.0.2", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q=="],
+
+ "marked-terminal": ["marked-terminal@7.1.0", "", { "dependencies": { "ansi-escapes": "^7.0.0", "chalk": "^5.3.0", "cli-highlight": "^2.1.11", "cli-table3": "^0.6.5", "node-emoji": "^2.1.3", "supports-hyperlinks": "^3.0.0" }, "peerDependencies": { "marked": ">=1 <14" } }, "sha512-+pvwa14KZL74MVXjYdPR3nSInhGhNvPce/3mqLVZT2oUvt654sL1XImFuLZ1pkA866IYZ3ikDTOFUIC7XzpZZg=="],
+
+ "meow": ["meow@12.1.1", "", {}, "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw=="],
+
+ "merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="],
+
+ "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
+
+ "micromatch": ["micromatch@4.0.7", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q=="],
+
+ "mime": ["mime@4.0.4", "", { "bin": { "mime": "bin/cli.js" } }, "sha512-v8yqInVjhXyqP6+Kw4fV3ZzeMRqEW6FotRsKXjRS5VMTNIuXsdRoAvklpoRgSqXm6o9VNH4/C0mgedko9DdLsQ=="],
+
+ "mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
+
+ "minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
+
+ "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
+
+ "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
+
+ "minipass-collect": ["minipass-collect@2.0.1", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw=="],
+
+ "minipass-fetch": ["minipass-fetch@3.0.5", "", { "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^1.0.3", "minizlib": "^2.1.2" }, "optionalDependencies": { "encoding": "^0.1.13" } }, "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg=="],
+
+ "minipass-flush": ["minipass-flush@1.0.5", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw=="],
+
+ "minipass-pipeline": ["minipass-pipeline@1.2.4", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A=="],
+
+ "minipass-sized": ["minipass-sized@1.0.3", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g=="],
+
+ "minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="],
+
+ "mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="],
+
+ "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
+
+ "mute-stream": ["mute-stream@1.0.0", "", {}, "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA=="],
+
+ "mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="],
+
+ "negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="],
+
+ "neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="],
+
+ "nerf-dart": ["nerf-dart@1.0.0", "", {}, "sha512-EZSPZB70jiVsivaBLYDCyntd5eH8NTSMOn3rB+HxwdmKThGELLdYv8qVIMWvZEFy9w8ZZpW9h9OB32l1rGtj7g=="],
+
+ "node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="],
+
+ "node-emoji": ["node-emoji@2.1.3", "", { "dependencies": { "@sindresorhus/is": "^4.6.0", "char-regex": "^1.0.2", "emojilib": "^2.4.0", "skin-tone": "^2.0.0" } }, "sha512-E2WEOVsgs7O16zsURJ/eH8BqhF029wGpEOnv7Urwdo2wmQanOACwJQh0devF9D9RhoZru0+9JXIS0dBXIAz+lA=="],
+
+ "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
+
+ "node-gyp": ["node-gyp@10.2.0", "", { "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", "glob": "^10.3.10", "graceful-fs": "^4.2.6", "make-fetch-happen": "^13.0.0", "nopt": "^7.0.0", "proc-log": "^4.1.0", "semver": "^7.3.5", "tar": "^6.2.1", "which": "^4.0.0" }, "bin": { "node-gyp": "bin/node-gyp.js" } }, "sha512-sp3FonBAaFe4aYTcFdZUn2NYkbP7xroPGYvQmP4Nl5PxamznItBnNCgjrVTKrEfQynInMsJvZrdmqUnysCJ8rw=="],
+
+ "nopt": ["nopt@7.2.1", "", { "dependencies": { "abbrev": "^2.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w=="],
+
+ "normalize-package-data": ["normalize-package-data@6.0.2", "", { "dependencies": { "hosted-git-info": "^7.0.0", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4" } }, "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g=="],
+
+ "normalize-url": ["normalize-url@8.0.1", "", {}, "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w=="],
+
+ "npm": ["npm@10.8.2", "", { "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/arborist": "^7.5.4", "@npmcli/config": "^8.3.4", "@npmcli/fs": "^3.1.1", "@npmcli/map-workspaces": "^3.0.6", "@npmcli/package-json": "^5.2.0", "@npmcli/promise-spawn": "^7.0.2", "@npmcli/redact": "^2.0.1", "@npmcli/run-script": "^8.1.0", "@sigstore/tuf": "^2.3.4", "abbrev": "^2.0.0", "archy": "~1.0.0", "cacache": "^18.0.3", "chalk": "^5.3.0", "ci-info": "^4.0.0", "cli-columns": "^4.0.0", "fastest-levenshtein": "^1.0.16", "fs-minipass": "^3.0.3", "glob": "^10.4.2", "graceful-fs": "^4.2.11", "hosted-git-info": "^7.0.2", "ini": "^4.1.3", "init-package-json": "^6.0.3", "is-cidr": "^5.1.0", "json-parse-even-better-errors": "^3.0.2", "libnpmaccess": "^8.0.6", "libnpmdiff": "^6.1.4", "libnpmexec": "^8.1.3", "libnpmfund": "^5.0.12", "libnpmhook": "^10.0.5", "libnpmorg": "^6.0.6", "libnpmpack": "^7.0.4", "libnpmpublish": "^9.0.9", "libnpmsearch": "^7.0.6", "libnpmteam": "^6.0.5", "libnpmversion": "^6.0.3", "make-fetch-happen": "^13.0.1", "minimatch": "^9.0.5", "minipass": "^7.1.1", "minipass-pipeline": "^1.2.4", "ms": "^2.1.2", "node-gyp": "^10.1.0", "nopt": "^7.2.1", "normalize-package-data": "^6.0.2", "npm-audit-report": "^5.0.0", "npm-install-checks": "^6.3.0", "npm-package-arg": "^11.0.2", "npm-pick-manifest": "^9.1.0", "npm-profile": "^10.0.0", "npm-registry-fetch": "^17.1.0", "npm-user-validate": "^2.0.1", "p-map": "^4.0.0", "pacote": "^18.0.6", "parse-conflict-json": "^3.0.1", "proc-log": "^4.2.0", "qrcode-terminal": "^0.12.0", "read": "^3.0.1", "semver": "^7.6.2", "spdx-expression-parse": "^4.0.0", "ssri": "^10.0.6", "supports-color": "^9.4.0", "tar": "^6.2.1", "text-table": "~0.2.0", "tiny-relative-date": "^1.3.0", "treeverse": "^3.0.0", "validate-npm-package-name": "^5.0.1", "which": "^4.0.0", "write-file-atomic": "^5.0.1" }, "bin": { "npm": "bin/npm-cli.js", "npx": "bin/npx-cli.js" } }, "sha512-x/AIjFIKRllrhcb48dqUNAAZl0ig9+qMuN91RpZo3Cb2+zuibfh+KISl6+kVVyktDz230JKc208UkQwwMqyB+w=="],
+
+ "npm-audit-report": ["npm-audit-report@5.0.0", "", {}, "sha512-EkXrzat7zERmUhHaoren1YhTxFwsOu5jypE84k6632SXTHcQE1z8V51GC6GVZt8LxkC+tbBcKMUBZAgk8SUSbw=="],
+
+ "npm-bundled": ["npm-bundled@3.0.1", "", { "dependencies": { "npm-normalize-package-bin": "^3.0.0" } }, "sha512-+AvaheE/ww1JEwRHOrn4WHNzOxGtVp+adrg2AeZS/7KuxGUYFuBta98wYpfHBbJp6Tg6j1NKSEVHNcfZzJHQwQ=="],
+
+ "npm-install-checks": ["npm-install-checks@6.3.0", "", { "dependencies": { "semver": "^7.1.1" } }, "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw=="],
+
+ "npm-normalize-package-bin": ["npm-normalize-package-bin@3.0.1", "", {}, "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ=="],
+
+ "npm-package-arg": ["npm-package-arg@11.0.3", "", { "dependencies": { "hosted-git-info": "^7.0.0", "proc-log": "^4.0.0", "semver": "^7.3.5", "validate-npm-package-name": "^5.0.0" } }, "sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw=="],
+
+ "npm-packlist": ["npm-packlist@8.0.2", "", { "dependencies": { "ignore-walk": "^6.0.4" } }, "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA=="],
+
+ "npm-pick-manifest": ["npm-pick-manifest@9.1.0", "", { "dependencies": { "npm-install-checks": "^6.0.0", "npm-normalize-package-bin": "^3.0.0", "npm-package-arg": "^11.0.0", "semver": "^7.3.5" } }, "sha512-nkc+3pIIhqHVQr085X9d2JzPzLyjzQS96zbruppqC9aZRm/x8xx6xhI98gHtsfELP2bE+loHq8ZaHFHhe+NauA=="],
+
+ "npm-profile": ["npm-profile@10.0.0", "", { "dependencies": { "npm-registry-fetch": "^17.0.1", "proc-log": "^4.0.0" } }, "sha512-DXnge3nHYnEnPxmVd/kPmgcXKXwVUqFihGnU+EJUiu5mIOs3awq6zEm0rRp3kSQNhFsoqdLu8L1TIfRyeBOCog=="],
+
+ "npm-registry-fetch": ["npm-registry-fetch@17.1.0", "", { "dependencies": { "@npmcli/redact": "^2.0.0", "jsonparse": "^1.3.1", "make-fetch-happen": "^13.0.0", "minipass": "^7.0.2", "minipass-fetch": "^3.0.0", "minizlib": "^2.1.2", "npm-package-arg": "^11.0.0", "proc-log": "^4.0.0" } }, "sha512-5+bKQRH0J1xG1uZ1zMNvxW0VEyoNWgJpY9UDuluPFLKDfJ9u2JmmjmTJV1srBGQOROfdBMiVvnH2Zvpbm+xkVA=="],
+
+ "npm-run-path": ["npm-run-path@6.0.0", "", { "dependencies": { "path-key": "^4.0.0", "unicorn-magic": "^0.3.0" } }, "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA=="],
+
+ "npm-user-validate": ["npm-user-validate@2.0.1", "", {}, "sha512-d17PKaF2h8LSGFl5j4b1gHOJt1fgH7YUcCm1kNSJvaLWWKXlBsuUvx0bBEkr0qhsVA9XP5LtRZ83hdlhm2QkgA=="],
+
+ "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
+
+ "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
+
+ "onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="],
+
+ "opencollective-postinstall": ["opencollective-postinstall@2.0.3", "", { "bin": { "opencollective-postinstall": "index.js" } }, "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q=="],
+
+ "p-each-series": ["p-each-series@3.0.0", "", {}, "sha512-lastgtAdoH9YaLyDa5i5z64q+kzOcQHsQ5SsZJD3q0VEyI8mq872S3geuNbRUQLVAE9siMfgKrpj7MloKFHruw=="],
+
+ "p-filter": ["p-filter@4.1.0", "", { "dependencies": { "p-map": "^7.0.1" } }, "sha512-37/tPdZ3oJwHaS3gNJdenCDB3Tz26i9sjhnguBtvN0vYlRIiDNnvTWkuh+0hETV9rLPdJ3rlL3yVOYPIAnM8rw=="],
+
+ "p-is-promise": ["p-is-promise@3.0.0", "", {}, "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ=="],
+
+ "p-limit": ["p-limit@1.3.0", "", { "dependencies": { "p-try": "^1.0.0" } }, "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q=="],
+
+ "p-locate": ["p-locate@2.0.0", "", { "dependencies": { "p-limit": "^1.1.0" } }, "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg=="],
+
+ "p-map": ["p-map@7.0.2", "", {}, "sha512-z4cYYMMdKHzw4O5UkWJImbZynVIo0lSGTXc7bzB1e/rrDqkgGUNysK/o4bTr+0+xKvvLoTyGqYC4Fgljy9qe1Q=="],
+
+ "p-reduce": ["p-reduce@2.1.0", "", {}, "sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw=="],
+
+ "p-try": ["p-try@1.0.0", "", {}, "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww=="],
+
+ "package-json-from-dist": ["package-json-from-dist@1.0.0", "", {}, "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw=="],
+
+ "pacote": ["pacote@18.0.6", "", { "dependencies": { "@npmcli/git": "^5.0.0", "@npmcli/installed-package-contents": "^2.0.1", "@npmcli/package-json": "^5.1.0", "@npmcli/promise-spawn": "^7.0.0", "@npmcli/run-script": "^8.0.0", "cacache": "^18.0.0", "fs-minipass": "^3.0.0", "minipass": "^7.0.2", "npm-package-arg": "^11.0.0", "npm-packlist": "^8.0.0", "npm-pick-manifest": "^9.0.0", "npm-registry-fetch": "^17.0.0", "proc-log": "^4.0.0", "promise-retry": "^2.0.1", "sigstore": "^2.2.0", "ssri": "^10.0.0", "tar": "^6.1.11" }, "bin": { "pacote": "bin/index.js" } }, "sha512-+eK3G27SMwsB8kLIuj4h1FUhHtwiEUo21Tw8wNjmvdlpOEr613edv+8FUsTj/4F/VN5ywGE19X18N7CC2EJk6A=="],
+
+ "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="],
+
+ "parse-conflict-json": ["parse-conflict-json@3.0.1", "", { "dependencies": { "json-parse-even-better-errors": "^3.0.0", "just-diff": "^6.0.0", "just-diff-apply": "^5.2.0" } }, "sha512-01TvEktc68vwbJOtWZluyWeVGWjP+bZwXtPDMQVbBKzbJ/vZBif0L69KH1+cHv1SZ6e0FKLvjyHe8mqsIqYOmw=="],
+
+ "parse-duration": ["parse-duration@1.1.2", "", {}, "sha512-p8EIONG8L0u7f8GFgfVlL4n8rnChTt8O5FSxgxMz2tjc9FMP199wxVKVB6IbKx11uTbKHACSvaLVIKNnoeNR/A=="],
+
+ "parse-json": ["parse-json@5.2.0", "", { "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" } }, "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg=="],
+
+ "parse-ms": ["parse-ms@4.0.0", "", {}, "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw=="],
+
+ "parse5": ["parse5@5.1.1", "", {}, "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug=="],
+
+ "parse5-htmlparser2-tree-adapter": ["parse5-htmlparser2-tree-adapter@6.0.1", "", { "dependencies": { "parse5": "^6.0.1" } }, "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA=="],
+
+ "path-exists": ["path-exists@5.0.0", "", {}, "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ=="],
+
+ "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
+
+ "path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
+
+ "path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="],
+
+ "picocolors": ["picocolors@1.0.1", "", {}, "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew=="],
+
+ "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
+
+ "pify": ["pify@3.0.0", "", {}, "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg=="],
+
+ "pkg-conf": ["pkg-conf@2.1.0", "", { "dependencies": { "find-up": "^2.0.0", "load-json-file": "^4.0.0" } }, "sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g=="],
+
+ "portainer-service-webhook": ["portainer-service-webhook@github:newarifrh/portainer-service-webhook#b6ec54b", { "dependencies": { "@actions/core": "^1.10.1" } }, "newarifrh-portainer-service-webhook-b6ec54b"],
+
+ "postcss-selector-parser": ["postcss-selector-parser@6.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg=="],
+
+ "pretty-ms": ["pretty-ms@9.1.0", "", { "dependencies": { "parse-ms": "^4.0.0" } }, "sha512-o1piW0n3tgKIKCwk2vpM/vOV13zjJzvP37Ioze54YlTHE06m4tjEbzg9WsKkvTuyYln2DHjo5pY4qrZGI0otpw=="],
+
+ "proc-log": ["proc-log@4.2.0", "", {}, "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA=="],
+
+ "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="],
+
+ "proggy": ["proggy@2.0.0", "", {}, "sha512-69agxLtnI8xBs9gUGqEnK26UfiexpHy+KUpBQWabiytQjnn5wFY8rklAi7GRfABIuPNnQ/ik48+LGLkYYJcy4A=="],
+
+ "promise-all-reject-late": ["promise-all-reject-late@1.0.1", "", {}, "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw=="],
+
+ "promise-call-limit": ["promise-call-limit@3.0.1", "", {}, "sha512-utl+0x8gIDasV5X+PI5qWEPqH6fJS0pFtQ/4gZ95xfEFb/89dmh+/b895TbFDBLiafBvxD/PGTKfvxl4kH/pQg=="],
+
+ "promise-inflight": ["promise-inflight@1.0.1", "", {}, "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g=="],
+
+ "promise-limit": ["promise-limit@2.7.0", "", {}, "sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw=="],
+
+ "promise-retry": ["promise-retry@2.0.1", "", { "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" } }, "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g=="],
+
+ "promzard": ["promzard@1.0.2", "", { "dependencies": { "read": "^3.0.1" } }, "sha512-2FPputGL+mP3jJ3UZg/Dl9YOkovB7DX0oOr+ck5QbZ5MtORtds8k/BZdn+02peDLI8/YWbmzx34k5fA+fHvCVQ=="],
+
+ "proto-list": ["proto-list@1.2.4", "", {}, "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA=="],
+
+ "pump": ["pump@3.0.0", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww=="],
+
+ "qrcode-terminal": ["qrcode-terminal@0.12.0", "", { "bin": { "qrcode-terminal": "./bin/qrcode-terminal.js" } }, "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ=="],
+
+ "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
+
+ "rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="],
+
+ "read": ["read@3.0.1", "", { "dependencies": { "mute-stream": "^1.0.0" } }, "sha512-SLBrDU/Srs/9EoWhU5GdbAoxG1GzpQHo/6qiGItaoLJ1thmYpcNIM1qISEUvyHBzfGlWIyd6p2DNi1oV1VmAuw=="],
+
+ "read-cmd-shim": ["read-cmd-shim@4.0.0", "", {}, "sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q=="],
+
+ "read-package-json-fast": ["read-package-json-fast@3.0.2", "", { "dependencies": { "json-parse-even-better-errors": "^3.0.0", "npm-normalize-package-bin": "^3.0.0" } }, "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw=="],
+
+ "read-package-up": ["read-package-up@11.0.0", "", { "dependencies": { "find-up-simple": "^1.0.0", "read-pkg": "^9.0.0", "type-fest": "^4.6.0" } }, "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ=="],
+
+ "read-pkg": ["read-pkg@9.0.1", "", { "dependencies": { "@types/normalize-package-data": "^2.4.3", "normalize-package-data": "^6.0.0", "parse-json": "^8.0.0", "type-fest": "^4.6.0", "unicorn-magic": "^0.1.0" } }, "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA=="],
+
+ "read-pkg-up": ["read-pkg-up@11.0.0", "", { "dependencies": { "find-up-simple": "^1.0.0", "read-pkg": "^9.0.0", "type-fest": "^4.6.0" } }, "sha512-LOVbvF1Q0SZdjClSefZ0Nz5z8u+tIE7mV5NibzmE9VYmDe9CaBbAVtz1veOSZbofrdsilxuDAYnFenukZVp8/Q=="],
+
+ "readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
+
+ "regenerator-runtime": ["regenerator-runtime@0.13.11", "", {}, "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="],
+
+ "registry-auth-token": ["registry-auth-token@5.0.2", "", { "dependencies": { "@pnpm/npm-conf": "^2.1.0" } }, "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ=="],
+
+ "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="],
+
+ "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
+
+ "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="],
+
+ "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="],
+
+ "retry": ["retry@0.12.0", "", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="],
+
+ "reusify": ["reusify@1.0.4", "", {}, "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="],
+
+ "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
+
+ "rxjs": ["rxjs@7.8.1", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg=="],
+
+ "safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
+
+ "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
+
+ "semantic-release": ["semantic-release@24.2.3", "", { "dependencies": { "@semantic-release/commit-analyzer": "^13.0.0-beta.1", "@semantic-release/error": "^4.0.0", "@semantic-release/github": "^11.0.0", "@semantic-release/npm": "^12.0.0", "@semantic-release/release-notes-generator": "^14.0.0-beta.1", "aggregate-error": "^5.0.0", "cosmiconfig": "^9.0.0", "debug": "^4.0.0", "env-ci": "^11.0.0", "execa": "^9.0.0", "figures": "^6.0.0", "find-versions": "^6.0.0", "get-stream": "^6.0.0", "git-log-parser": "^1.2.0", "hook-std": "^3.0.0", "hosted-git-info": "^8.0.0", "import-from-esm": "^2.0.0", "lodash-es": "^4.17.21", "marked": "^12.0.0", "marked-terminal": "^7.0.0", "micromatch": "^4.0.2", "p-each-series": "^3.0.0", "p-reduce": "^3.0.0", "read-package-up": "^11.0.0", "resolve-from": "^5.0.0", "semver": "^7.3.2", "semver-diff": "^4.0.0", "signale": "^1.2.1", "yargs": "^17.5.1" }, "bin": { "semantic-release": "bin/semantic-release.js" } }, "sha512-KRhQG9cUazPavJiJEFIJ3XAMjgfd0fcK3B+T26qOl8L0UG5aZUjeRfREO0KM5InGtYwxqiiytkJrbcYoLDEv0A=="],
+
+ "semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
+
+ "semver-diff": ["semver-diff@4.0.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA=="],
+
+ "semver-regex": ["semver-regex@4.0.5", "", {}, "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw=="],
+
+ "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
+
+ "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
+
+ "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
+
+ "signale": ["signale@1.4.0", "", { "dependencies": { "chalk": "^2.3.2", "figures": "^2.0.0", "pkg-conf": "^2.1.0" } }, "sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w=="],
+
+ "sigstore": ["sigstore@2.3.1", "", { "dependencies": { "@sigstore/bundle": "^2.3.2", "@sigstore/core": "^1.0.0", "@sigstore/protobuf-specs": "^0.3.2", "@sigstore/sign": "^2.3.2", "@sigstore/tuf": "^2.3.4", "@sigstore/verify": "^1.2.1" } }, "sha512-8G+/XDU8wNsJOQS5ysDVO0Etg9/2uA5gR9l4ZwijjlwxBcrU6RPfwi2+jJmbP+Ap1Hlp/nVAaEO4Fj22/SL2gQ=="],
+
+ "skin-tone": ["skin-tone@2.0.0", "", { "dependencies": { "unicode-emoji-modifier-base": "^1.0.0" } }, "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA=="],
+
+ "slash": ["slash@5.1.0", "", {}, "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg=="],
+
+ "smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="],
+
+ "socks": ["socks@2.8.3", "", { "dependencies": { "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" } }, "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw=="],
+
+ "socks-proxy-agent": ["socks-proxy-agent@8.0.4", "", { "dependencies": { "agent-base": "^7.1.1", "debug": "^4.3.4", "socks": "^2.8.3" } }, "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw=="],
+
+ "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
+
+ "source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="],
+
+ "spawn-error-forwarder": ["spawn-error-forwarder@1.0.0", "", {}, "sha512-gRjMgK5uFjbCvdibeGJuy3I5OYz6VLoVdsOJdA6wV0WlfQVLFueoqMxwwYD9RODdgb6oUIvlRlsyFSiQkMKu0g=="],
+
+ "spdx-correct": ["spdx-correct@3.2.0", "", { "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA=="],
+
+ "spdx-exceptions": ["spdx-exceptions@2.5.0", "", {}, "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="],
+
+ "spdx-expression-parse": ["spdx-expression-parse@4.0.0", "", { "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ=="],
+
+ "spdx-license-ids": ["spdx-license-ids@3.0.18", "", {}, "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ=="],
+
+ "split2": ["split2@1.0.0", "", { "dependencies": { "through2": "~2.0.0" } }, "sha512-NKywug4u4pX/AZBB1FCPzZ6/7O+Xhz1qMVbzTvvKvikjO99oPN87SkK08mEY9P63/5lWjK+wgOOgApnTg5r6qg=="],
+
+ "sprintf-js": ["sprintf-js@1.1.3", "", {}, "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="],
+
+ "ssri": ["ssri@10.0.6", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ=="],
+
+ "stream-buffers": ["stream-buffers@3.0.3", "", {}, "sha512-pqMqwQCso0PBJt2PQmDO0cFj0lyqmiwOMiMSkVtRokl7e+ZTRYgDHKnuZNbqjiJXgsg4nuqtD/zxuo9KqTp0Yw=="],
+
+ "stream-combiner2": ["stream-combiner2@1.1.1", "", { "dependencies": { "duplexer2": "~0.1.0", "readable-stream": "^2.0.2" } }, "sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw=="],
+
+ "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
+
+ "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
+
+ "string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
+
+ "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
+
+ "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
+
+ "strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="],
+
+ "strip-final-newline": ["strip-final-newline@4.0.0", "", {}, "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw=="],
+
+ "strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="],
+
+ "super-regex": ["super-regex@1.0.0", "", { "dependencies": { "function-timeout": "^1.0.1", "time-span": "^5.1.0" } }, "sha512-CY8u7DtbvucKuquCmOFEKhr9Besln7n9uN8eFbwcoGYWXOMW07u2o8njWaiXt11ylS3qoGF55pILjRmPlbodyg=="],
+
+ "supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="],
+
+ "supports-hyperlinks": ["supports-hyperlinks@3.0.0", "", { "dependencies": { "has-flag": "^4.0.0", "supports-color": "^7.0.0" } }, "sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA=="],
+
+ "tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="],
+
+ "temp-dir": ["temp-dir@3.0.0", "", {}, "sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw=="],
+
+ "tempy": ["tempy@3.1.0", "", { "dependencies": { "is-stream": "^3.0.0", "temp-dir": "^3.0.0", "type-fest": "^2.12.2", "unique-string": "^3.0.0" } }, "sha512-7jDLIdD2Zp0bDe5r3D2qtkd1QOCacylBuL7oa4udvN6v2pqr4+LcCr67C8DR1zkpaZ8XosF5m1yQSabKAW6f2g=="],
+
+ "tesseract.js": ["tesseract.js@5.1.1", "", { "dependencies": { "bmp-js": "^0.1.0", "idb-keyval": "^6.2.0", "is-electron": "^2.2.2", "is-url": "^1.2.4", "node-fetch": "^2.6.9", "opencollective-postinstall": "^2.0.3", "regenerator-runtime": "^0.13.3", "tesseract.js-core": "^5.1.1", "wasm-feature-detect": "^1.2.11", "zlibjs": "^0.3.1" } }, "sha512-lzVl/Ar3P3zhpUT31NjqeCo1f+D5+YfpZ5J62eo2S14QNVOmHBTtbchHm/YAbOOOzCegFnKf4B3Qih9LuldcYQ=="],
+
+ "tesseract.js-core": ["tesseract.js-core@5.1.1", "", {}, "sha512-KX3bYSU5iGcO1XJa+QGPbi+Zjo2qq6eBhNjSGR5E5q0JtzkoipJKOUQD7ph8kFyteCEfEQ0maWLu8MCXtvX5uQ=="],
+
+ "text-extensions": ["text-extensions@2.4.0", "", {}, "sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g=="],
+
+ "text-table": ["text-table@0.2.0", "", {}, "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw=="],
+
+ "thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="],
+
+ "thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="],
+
+ "through": ["through@2.3.8", "", {}, "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="],
+
+ "through2": ["through2@2.0.5", "", { "dependencies": { "readable-stream": "~2.3.6", "xtend": "~4.0.1" } }, "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ=="],
+
+ "time-span": ["time-span@5.1.0", "", { "dependencies": { "convert-hrtime": "^5.0.0" } }, "sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA=="],
+
+ "tiny-relative-date": ["tiny-relative-date@1.3.0", "", {}, "sha512-MOQHpzllWxDCHHaDno30hhLfbouoYlOI8YlMNtvKe1zXbjEVhbcEovQxvZrPvtiYW630GQDoMMarCnjfyfHA+A=="],
+
+ "tinyexec": ["tinyexec@0.3.0", "", {}, "sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg=="],
+
+ "tinytim": ["tinytim@0.1.1", "", {}, "sha512-NIpsp9lBIxPNzB++HnMmUd4byzJSVbbO4F+As1Gb1IG/YQT5QvmBDjpx8SpDS8fhGC+t+Qw8ldQgbcAIaU+2cA=="],
+
+ "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
+
+ "toposource": ["toposource@1.2.0", "", {}, "sha512-sb8zWvXUWJ+jqnHM/+ud7muOT3wi0lVL/DFHH+CxTViSngzhRrIm8nensUOcxuLUNAMdsfE9DxZjLX3GhCTJKg=="],
+
+ "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="],
+
+ "tracer": ["tracer@1.3.0", "", { "dependencies": { "colors": "1.4.0", "dateformat": "4.5.1", "mkdirp": "^1.0.4", "tinytim": "0.1.1" } }, "sha512-8G2okIuUNThM1W8HU9YUCsQgxROw9VpewE2f8Tsw3B90b0acvBiATqnUIvv07qG/aBTs7ALDr7tLVUVD86kPPA=="],
+
+ "traverse": ["traverse@0.6.8", "", {}, "sha512-aXJDbk6SnumuaZSANd21XAo15ucCDE38H4fkqiGsc3MhCK+wOlZvLP9cB/TvpHT0mOyWgC4Z8EwRlzqYSUzdsA=="],
+
+ "treeverse": ["treeverse@3.0.0", "", {}, "sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ=="],
+
+ "ts-mixer": ["ts-mixer@6.0.4", "", {}, "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA=="],
+
+ "tslib": ["tslib@2.6.3", "", {}, "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ=="],
+
+ "tuf-js": ["tuf-js@2.2.1", "", { "dependencies": { "@tufjs/models": "2.0.1", "debug": "^4.3.4", "make-fetch-happen": "^13.0.1" } }, "sha512-GwIJau9XaA8nLVbUXsN3IlFi7WmQ48gBUrl3FTkkL/XLu/POhBzfmX9hd33FNMX1qAsfl6ozO1iMmW9NC8YniA=="],
+
+ "tunnel": ["tunnel@0.0.6", "", {}, "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="],
+
+ "turbo": ["turbo@2.5.0", "", { "optionalDependencies": { "turbo-darwin-64": "2.5.0", "turbo-darwin-arm64": "2.5.0", "turbo-linux-64": "2.5.0", "turbo-linux-arm64": "2.5.0", "turbo-windows-64": "2.5.0", "turbo-windows-arm64": "2.5.0" }, "bin": { "turbo": "bin/turbo" } }, "sha512-PvSRruOsitjy6qdqwIIyolv99+fEn57gP6gn4zhsHTEcCYgXPhv6BAxzAjleS8XKpo+Y582vTTA9nuqYDmbRuA=="],
+
+ "turbo-darwin-64": ["turbo-darwin-64@2.5.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-fP1hhI9zY8hv0idym3hAaXdPi80TLovmGmgZFocVAykFtOxF+GlfIgM/l4iLAV9ObIO4SUXPVWHeBZQQ+Hpjag=="],
+
+ "turbo-darwin-arm64": ["turbo-darwin-arm64@2.5.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-p9sYq7kXH7qeJwIQE86cOWv/xNqvow846l6c/qWc26Ib1ci5W7V0sI5thsrP3eH+VA0d+SHalTKg5SQXgNQBWA=="],
+
+ "turbo-linux-64": ["turbo-linux-64@2.5.0", "", { "os": "linux", "cpu": "x64" }, "sha512-1iEln2GWiF3iPPPS1HQJT6ZCFXynJPd89gs9SkggH2EJsj3eRUSVMmMC8y6d7bBbhBFsiGGazwFIYrI12zs6uQ=="],
+
+ "turbo-linux-arm64": ["turbo-linux-arm64@2.5.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-bKBcbvuQHmsX116KcxHJuAcppiiBOfivOObh2O5aXNER6mce7YDDQJy00xQQNp1DhEfcSV2uOsvb3O3nN2cbcA=="],
+
+ "turbo-windows-64": ["turbo-windows-64@2.5.0", "", { "os": "win32", "cpu": "x64" }, "sha512-9BCo8oQ7BO7J0K913Czbc3tw8QwLqn2nTe4E47k6aVYkM12ASTScweXPTuaPFP5iYXAT6z5Dsniw704Ixa5eGg=="],
+
+ "turbo-windows-arm64": ["turbo-windows-arm64@2.5.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-OUHCV+ueXa3UzfZ4co/ueIHgeq9B2K48pZwIxKSm5VaLVuv8M13MhM7unukW09g++dpdrrE1w4IOVgxKZ0/exg=="],
+
+ "type-fest": ["type-fest@4.23.0", "", {}, "sha512-ZiBujro2ohr5+Z/hZWHESLz3g08BBdrdLMieYFULJO+tWc437sn8kQsWLJoZErY8alNhxre9K4p3GURAG11n+w=="],
+
+ "typed-emitter": ["typed-emitter@2.1.0", "", { "optionalDependencies": { "rxjs": "*" } }, "sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA=="],
+
+ "typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="],
+
+ "uglify-js": ["uglify-js@3.19.0", "", { "bin": { "uglifyjs": "bin/uglifyjs" } }, "sha512-wNKHUY2hYYkf6oSFfhwwiHo4WCHzHmzcXsqXYTN9ja3iApYIFbb2U6ics9hBcYLHcYGQoAlwnZlTrf3oF+BL/Q=="],
+
+ "undici": ["undici@6.21.1", "", {}, "sha512-q/1rj5D0/zayJB2FraXdaWxbhWiNKDvu8naDT2dl1yTlvJp4BLtOcp2a5BvgGNQpYYJzau7tf1WgKv3b+7mqpQ=="],
+
+ "undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
+
+ "unicode-emoji-modifier-base": ["unicode-emoji-modifier-base@1.0.0", "", {}, "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g=="],
+
+ "unicorn-magic": ["unicorn-magic@0.3.0", "", {}, "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA=="],
+
+ "unique-filename": ["unique-filename@3.0.0", "", { "dependencies": { "unique-slug": "^4.0.0" } }, "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g=="],
+
+ "unique-slug": ["unique-slug@4.0.0", "", { "dependencies": { "imurmurhash": "^0.1.4" } }, "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ=="],
+
+ "unique-string": ["unique-string@3.0.0", "", { "dependencies": { "crypto-random-string": "^4.0.0" } }, "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ=="],
+
+ "universal-user-agent": ["universal-user-agent@7.0.2", "", {}, "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q=="],
+
+ "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="],
+
+ "url-join": ["url-join@5.0.0", "", {}, "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA=="],
+
+ "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
+
+ "valibot": ["valibot@0.30.0", "", {}, "sha512-5POBdbSkM+3nvJ6ZlyQHsggisfRtyT4tVTo1EIIShs6qCdXJnyWU5TJ68vr8iTg5zpOLjXLRiBqNx+9zwZz/rA=="],
+
+ "validate-npm-package-license": ["validate-npm-package-license@3.0.4", "", { "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew=="],
+
+ "validate-npm-package-name": ["validate-npm-package-name@5.0.1", "", {}, "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ=="],
+
+ "walk-up-path": ["walk-up-path@3.0.1", "", {}, "sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA=="],
+
+ "wasm-feature-detect": ["wasm-feature-detect@1.6.2", "", {}, "sha512-4dnaZ+Fq/q+BbMlTIfaNS851i+0zmHzui++NUZdskESRu3xwB6g6x2FnGvBdWtpijqO5yuj1l+EUTJGc4S4DKg=="],
+
+ "web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="],
+
+ "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="],
+
+ "whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="],
+
+ "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
+
+ "wordwrap": ["wordwrap@1.0.0", "", {}, "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q=="],
+
+ "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
+
+ "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
+
+ "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
+
+ "write-file-atomic": ["write-file-atomic@5.0.1", "", { "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^4.0.1" } }, "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw=="],
+
+ "ws": ["ws@8.18.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w=="],
+
+ "xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="],
+
+ "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
+
+ "yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
+
+ "yargs": ["yargs@17.7.2", "", { "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" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
+
+ "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
+
+ "yocto-queue": ["yocto-queue@1.1.1", "", {}, "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g=="],
+
+ "yoctocolors": ["yoctocolors@2.1.1", "", {}, "sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ=="],
+
+ "zlibjs": ["zlibjs@0.3.1", "", {}, "sha512-+J9RrgTKOmlxFSDHo0pI1xM6BLVUv+o0ZT9ANtCxGkjIVCCUdx9alUF8Gm+dGLKbkkkidWIHFDZHDMpfITt4+w=="],
+
+ "@actions/http-client/undici": ["undici@5.28.4", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g=="],
+
+ "@babel/highlight/chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="],
+
+ "@codedependant/semantic-release-docker/execa": ["execa@4.1.0", "", { "dependencies": { "cross-spawn": "^7.0.0", "get-stream": "^5.0.0", "human-signals": "^1.1.1", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.0", "onetime": "^5.1.0", "signal-exit": "^3.0.2", "strip-final-newline": "^2.0.0" } }, "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA=="],
+
+ "@commitlint/format/chalk": ["chalk@5.3.0", "", {}, "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w=="],
+
+ "@commitlint/load/chalk": ["chalk@5.3.0", "", {}, "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w=="],
+
+ "@commitlint/parse/conventional-changelog-angular": ["conventional-changelog-angular@7.0.0", "", { "dependencies": { "compare-func": "^2.0.0" } }, "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ=="],
+
+ "@commitlint/parse/conventional-commits-parser": ["conventional-commits-parser@5.0.0", "", { "dependencies": { "JSONStream": "^1.3.5", "is-text-path": "^2.0.0", "meow": "^12.0.1", "split2": "^4.0.0" }, "bin": { "conventional-commits-parser": "cli.mjs" } }, "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA=="],
+
+ "@commitlint/top-level/find-up": ["find-up@7.0.0", "", { "dependencies": { "locate-path": "^7.2.0", "path-exists": "^5.0.0", "unicorn-magic": "^0.1.0" } }, "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g=="],
+
+ "@commitlint/types/chalk": ["chalk@5.3.0", "", {}, "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w=="],
+
+ "@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="],
+
+ "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
+
+ "@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
+
+ "@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="],
+
+ "@libsql/hrana-client/node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="],
+
+ "@libsql/isomorphic-ws/@types/ws": ["@types/ws@8.5.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-4+q7P5h3SpJxaBft0Dzpbr6lmMaqh0Jr2tbhJZ/luAwvD7ohSCniYkwz/pLxuT2h0EOa6QADgJj1Ko+TzRfZ+w=="],
+
+ "@libsql/isomorphic-ws/ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="],
+
+ "@npmcli/arborist/hosted-git-info": ["hosted-git-info@7.0.2", "", { "dependencies": { "lru-cache": "^10.0.1" } }, "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w=="],
+
+ "@npmcli/arborist/json-parse-even-better-errors": ["json-parse-even-better-errors@3.0.2", "", {}, "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ=="],
+
+ "@npmcli/arborist/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
+
+ "@npmcli/config/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
+
+ "@npmcli/fs/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
+
+ "@npmcli/git/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
+
+ "@npmcli/git/which": ["which@4.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="],
+
+ "@npmcli/metavuln-calculator/json-parse-even-better-errors": ["json-parse-even-better-errors@3.0.2", "", {}, "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ=="],
+
+ "@npmcli/metavuln-calculator/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
+
+ "@npmcli/package-json/hosted-git-info": ["hosted-git-info@7.0.2", "", { "dependencies": { "lru-cache": "^10.0.1" } }, "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w=="],
+
+ "@npmcli/package-json/json-parse-even-better-errors": ["json-parse-even-better-errors@3.0.2", "", {}, "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ=="],
+
+ "@npmcli/package-json/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
+
+ "@npmcli/promise-spawn/which": ["which@4.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="],
+
+ "@npmcli/run-script/which": ["which@4.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="],
+
+ "@pnpm/network.ca-file/graceful-fs": ["graceful-fs@4.2.10", "", {}, "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="],
+
+ "@saithodev/semantic-release-backmerge/debug": ["debug@4.3.5", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg=="],
+
+ "@saithodev/semantic-release-backmerge/execa": ["execa@5.1.1", "", { "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" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release": ["semantic-release@22.0.12", "", { "dependencies": { "@semantic-release/commit-analyzer": "^11.0.0", "@semantic-release/error": "^4.0.0", "@semantic-release/github": "^9.0.0", "@semantic-release/npm": "^11.0.0", "@semantic-release/release-notes-generator": "^12.0.0", "aggregate-error": "^5.0.0", "cosmiconfig": "^8.0.0", "debug": "^4.0.0", "env-ci": "^10.0.0", "execa": "^8.0.0", "figures": "^6.0.0", "find-versions": "^5.1.0", "get-stream": "^6.0.0", "git-log-parser": "^1.2.0", "hook-std": "^3.0.0", "hosted-git-info": "^7.0.0", "import-from-esm": "^1.3.1", "lodash-es": "^4.17.21", "marked": "^9.0.0", "marked-terminal": "^6.0.0", "micromatch": "^4.0.2", "p-each-series": "^3.0.0", "p-reduce": "^3.0.0", "read-pkg-up": "^11.0.0", "resolve-from": "^5.0.0", "semver": "^7.3.2", "semver-diff": "^4.0.0", "signale": "^1.2.1", "yargs": "^17.5.1" }, "bin": { "semantic-release": "bin/semantic-release.js" } }, "sha512-0mhiCR/4sZb00RVFJIUlMuiBkW3NMpVIW2Gse7noqEMoFGkvfPPAImEQbkBV8xga4KOPP4FdTRYuLLy32R1fPw=="],
+
+ "@semantic-release/commit-analyzer/debug": ["debug@4.3.5", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg=="],
+
+ "@semantic-release/commit-analyzer/import-from-esm": ["import-from-esm@1.3.4", "", { "dependencies": { "debug": "^4.3.4", "import-meta-resolve": "^4.0.0" } }, "sha512-7EyUlPFC0HOlBDpUFGfYstsU7XHxZJKAAMzCT8wZ0hMW7b+hG51LIKTDcsgtz8Pu6YC0HqRVbX+rVUtsGMUKvg=="],
+
+ "@semantic-release/exec/debug": ["debug@4.3.5", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg=="],
+
+ "@semantic-release/exec/execa": ["execa@5.1.1", "", { "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" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="],
+
+ "@semantic-release/git/debug": ["debug@4.3.5", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg=="],
+
+ "@semantic-release/git/execa": ["execa@5.1.1", "", { "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" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="],
+
+ "@semantic-release/github/@semantic-release/error": ["@semantic-release/error@4.0.0", "", {}, "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ=="],
+
+ "@semantic-release/github/aggregate-error": ["aggregate-error@5.0.0", "", { "dependencies": { "clean-stack": "^5.2.0", "indent-string": "^5.0.0" } }, "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw=="],
+
+ "@semantic-release/github/debug": ["debug@4.3.5", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg=="],
+
+ "@semantic-release/npm/@semantic-release/error": ["@semantic-release/error@4.0.0", "", {}, "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ=="],
+
+ "@semantic-release/npm/aggregate-error": ["aggregate-error@5.0.0", "", { "dependencies": { "clean-stack": "^5.2.0", "indent-string": "^5.0.0" } }, "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw=="],
+
+ "@semantic-release/npm/execa": ["execa@9.3.0", "", { "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "cross-spawn": "^7.0.3", "figures": "^6.1.0", "get-stream": "^9.0.0", "human-signals": "^7.0.0", "is-plain-obj": "^4.1.0", "is-stream": "^4.0.1", "npm-run-path": "^5.2.0", "pretty-ms": "^9.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^4.0.0", "yoctocolors": "^2.0.0" } }, "sha512-l6JFbqnHEadBoVAVpN5dl2yCyfX28WoBAGaoQcNmLLSedOxTxcn2Qa83s8I/PA5i56vWru2OHOtrwF7Om2vqlg=="],
+
+ "@semantic-release/npm/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
+
+ "@semantic-release/release-notes-generator/debug": ["debug@4.3.5", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg=="],
+
+ "@semantic-release/release-notes-generator/get-stream": ["get-stream@7.0.1", "", {}, "sha512-3M8C1EOFN6r8AMUhwUAACIoXZJEOufDU5+0gFFN5uNs6XYOralD2Pqkl7m046va6x77FwposWXbAhPPIOus7mQ=="],
+
+ "@semantic-release/release-notes-generator/import-from-esm": ["import-from-esm@1.3.4", "", { "dependencies": { "debug": "^4.3.4", "import-meta-resolve": "^4.0.0" } }, "sha512-7EyUlPFC0HOlBDpUFGfYstsU7XHxZJKAAMzCT8wZ0hMW7b+hG51LIKTDcsgtz8Pu6YC0HqRVbX+rVUtsGMUKvg=="],
+
+ "agent-base/debug": ["debug@4.3.5", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg=="],
+
+ "bun-types/@types/ws": ["@types/ws@8.5.12", "", { "dependencies": { "@types/node": "*" } }, "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ=="],
+
+ "cacache/p-map": ["p-map@4.0.0", "", { "dependencies": { "aggregate-error": "^3.0.0" } }, "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ=="],
+
+ "cli-highlight/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
+
+ "cli-highlight/yargs": ["yargs@16.2.0", "", { "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.0", "y18n": "^5.0.5", "yargs-parser": "^20.2.2" } }, "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw=="],
+
+ "config-chain/ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="],
+
+ "conventional-changelog-writer/meow": ["meow@13.2.0", "", {}, "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA=="],
+
+ "conventional-changelog-writer/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
+
+ "conventional-commits-parser/meow": ["meow@13.2.0", "", {}, "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA=="],
+
+ "crypto-random-string/type-fest": ["type-fest@1.4.0", "", {}, "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA=="],
+
+ "discord.js/@discordjs/collection": ["@discordjs/collection@1.5.3", "", {}, "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ=="],
+
+ "env-ci/execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="],
+
+ "esbuild-register/debug": ["debug@4.3.5", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg=="],
+
+ "execa/get-stream": ["get-stream@9.0.1", "", { "dependencies": { "@sec-ant/readable-stream": "^0.4.1", "is-stream": "^4.0.1" } }, "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA=="],
+
+ "git-raw-commits/split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="],
+
+ "global-directory/ini": ["ini@4.1.1", "", {}, "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g=="],
+
+ "globby/@sindresorhus/merge-streams": ["@sindresorhus/merge-streams@2.3.0", "", {}, "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg=="],
+
+ "globby/path-type": ["path-type@5.0.0", "", {}, "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg=="],
+
+ "globby/unicorn-magic": ["unicorn-magic@0.1.0", "", {}, "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ=="],
+
+ "http-proxy-agent/debug": ["debug@4.3.5", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg=="],
+
+ "https-proxy-agent/debug": ["debug@4.3.5", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg=="],
+
+ "import-fresh/resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
+
+ "import-from-esm/debug": ["debug@4.3.5", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg=="],
+
+ "init-package-json/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
+
+ "libnpmexec/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
+
+ "libnpmpublish/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
+
+ "libnpmversion/json-parse-even-better-errors": ["json-parse-even-better-errors@3.0.2", "", {}, "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ=="],
+
+ "libnpmversion/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
+
+ "load-json-file/parse-json": ["parse-json@4.0.0", "", { "dependencies": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" } }, "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw=="],
+
+ "locate-path/path-exists": ["path-exists@3.0.0", "", {}, "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ=="],
+
+ "marked-terminal/chalk": ["chalk@5.3.0", "", {}, "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w=="],
+
+ "minipass-flush/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
+
+ "minipass-pipeline/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
+
+ "minipass-sized/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
+
+ "minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
+
+ "node-gyp/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
+
+ "node-gyp/which": ["which@4.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="],
+
+ "normalize-package-data/hosted-git-info": ["hosted-git-info@7.0.2", "", { "dependencies": { "lru-cache": "^10.0.1" } }, "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w=="],
+
+ "normalize-package-data/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
+
+ "npm/chalk": ["chalk@5.3.0", "", {}, "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w=="],
+
+ "npm/hosted-git-info": ["hosted-git-info@7.0.2", "", { "dependencies": { "lru-cache": "^10.0.1" } }, "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w=="],
+
+ "npm/json-parse-even-better-errors": ["json-parse-even-better-errors@3.0.2", "", {}, "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ=="],
+
+ "npm/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
+
+ "npm/p-map": ["p-map@4.0.0", "", { "dependencies": { "aggregate-error": "^3.0.0" } }, "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ=="],
+
+ "npm/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
+
+ "npm/supports-color": ["supports-color@9.4.0", "", {}, "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw=="],
+
+ "npm/which": ["which@4.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="],
+
+ "npm-install-checks/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
+
+ "npm-package-arg/hosted-git-info": ["hosted-git-info@7.0.2", "", { "dependencies": { "lru-cache": "^10.0.1" } }, "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w=="],
+
+ "npm-package-arg/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
+
+ "npm-pick-manifest/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
+
+ "npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
+
+ "parse-conflict-json/json-parse-even-better-errors": ["json-parse-even-better-errors@3.0.2", "", {}, "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ=="],
+
+ "parse5-htmlparser2-tree-adapter/parse5": ["parse5@6.0.1", "", {}, "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="],
+
+ "rc/ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="],
+
+ "read-package-json-fast/json-parse-even-better-errors": ["json-parse-even-better-errors@3.0.2", "", {}, "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ=="],
+
+ "read-pkg/parse-json": ["parse-json@8.1.0", "", { "dependencies": { "@babel/code-frame": "^7.22.13", "index-to-position": "^0.1.2", "type-fest": "^4.7.1" } }, "sha512-rum1bPifK5SSar35Z6EKZuYPJx85pkNaFrxBK3mwdfSJ1/WKbYrjoW/zTPSjRRamfmVX1ACBIdFAO0VRErW/EA=="],
+
+ "read-pkg/unicorn-magic": ["unicorn-magic@0.1.0", "", {}, "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ=="],
+
+ "semantic-release/@semantic-release/error": ["@semantic-release/error@4.0.0", "", {}, "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ=="],
+
+ "semantic-release/aggregate-error": ["aggregate-error@5.0.0", "", { "dependencies": { "clean-stack": "^5.2.0", "indent-string": "^5.0.0" } }, "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw=="],
+
+ "semantic-release/debug": ["debug@4.3.5", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg=="],
+
+ "semantic-release/execa": ["execa@9.3.0", "", { "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "cross-spawn": "^7.0.3", "figures": "^6.1.0", "get-stream": "^9.0.0", "human-signals": "^7.0.0", "is-plain-obj": "^4.1.0", "is-stream": "^4.0.1", "npm-run-path": "^5.2.0", "pretty-ms": "^9.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^4.0.0", "yoctocolors": "^2.0.0" } }, "sha512-l6JFbqnHEadBoVAVpN5dl2yCyfX28WoBAGaoQcNmLLSedOxTxcn2Qa83s8I/PA5i56vWru2OHOtrwF7Om2vqlg=="],
+
+ "semantic-release/p-reduce": ["p-reduce@3.0.0", "", {}, "sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q=="],
+
+ "semantic-release/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
+
+ "semver-diff/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
+
+ "signale/chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="],
+
+ "signale/figures": ["figures@2.0.0", "", { "dependencies": { "escape-string-regexp": "^1.0.5" } }, "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA=="],
+
+ "socks-proxy-agent/debug": ["debug@4.3.5", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg=="],
+
+ "spdx-correct/spdx-expression-parse": ["spdx-expression-parse@3.0.1", "", { "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q=="],
+
+ "supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="],
+
+ "supports-hyperlinks/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
+
+ "tar/fs-minipass": ["fs-minipass@2.1.0", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg=="],
+
+ "tar/minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="],
+
+ "tempy/is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="],
+
+ "tempy/type-fest": ["type-fest@2.19.0", "", {}, "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA=="],
+
+ "tuf-js/debug": ["debug@4.3.5", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg=="],
+
+ "validate-npm-package-license/spdx-expression-parse": ["spdx-expression-parse@3.0.1", "", { "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q=="],
+
+ "wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
+
+ "wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
+
+ "@codedependant/semantic-release-docker/execa/get-stream": ["get-stream@5.2.0", "", { "dependencies": { "pump": "^3.0.0" } }, "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA=="],
+
+ "@codedependant/semantic-release-docker/execa/human-signals": ["human-signals@1.1.1", "", {}, "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw=="],
+
+ "@codedependant/semantic-release-docker/execa/is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="],
+
+ "@codedependant/semantic-release-docker/execa/npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="],
+
+ "@codedependant/semantic-release-docker/execa/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
+
+ "@codedependant/semantic-release-docker/execa/strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="],
+
+ "@commitlint/parse/conventional-commits-parser/split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="],
+
+ "@commitlint/top-level/find-up/locate-path": ["locate-path@7.2.0", "", { "dependencies": { "p-locate": "^6.0.0" } }, "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA=="],
+
+ "@commitlint/top-level/find-up/unicorn-magic": ["unicorn-magic@0.1.0", "", {}, "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.18.20", "", { "os": "android", "cpu": "arm64" }, "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.18.20", "", { "os": "android", "cpu": "x64" }, "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.18.20", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.18.20", "", { "os": "darwin", "cpu": "x64" }, "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.18.20", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.18.20", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.18.20", "", { "os": "linux", "cpu": "arm" }, "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.18.20", "", { "os": "linux", "cpu": "arm64" }, "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.18.20", "", { "os": "linux", "cpu": "ia32" }, "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.18.20", "", { "os": "linux", "cpu": "ppc64" }, "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.18.20", "", { "os": "linux", "cpu": "s390x" }, "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.18.20", "", { "os": "linux", "cpu": "x64" }, "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.18.20", "", { "os": "none", "cpu": "x64" }, "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.18.20", "", { "os": "openbsd", "cpu": "x64" }, "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.18.20", "", { "os": "sunos", "cpu": "x64" }, "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.18.20", "", { "os": "win32", "cpu": "arm64" }, "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.18.20", "", { "os": "win32", "cpu": "ia32" }, "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="],
+
+ "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
+
+ "@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.0.1", "", {}, "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA=="],
+
+ "@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
+
+ "@npmcli/git/which/isexe": ["isexe@3.1.1", "", {}, "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="],
+
+ "@npmcli/promise-spawn/which/isexe": ["isexe@3.1.1", "", {}, "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="],
+
+ "@npmcli/run-script/which/isexe": ["isexe@3.1.1", "", {}, "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="],
+
+ "@saithodev/semantic-release-backmerge/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
+
+ "@saithodev/semantic-release-backmerge/execa/human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="],
+
+ "@saithodev/semantic-release-backmerge/execa/is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="],
+
+ "@saithodev/semantic-release-backmerge/execa/npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="],
+
+ "@saithodev/semantic-release-backmerge/execa/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
+
+ "@saithodev/semantic-release-backmerge/execa/strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/commit-analyzer": ["@semantic-release/commit-analyzer@11.1.0", "", { "dependencies": { "conventional-changelog-angular": "^7.0.0", "conventional-commits-filter": "^4.0.0", "conventional-commits-parser": "^5.0.0", "debug": "^4.0.0", "import-from-esm": "^1.0.3", "lodash-es": "^4.17.21", "micromatch": "^4.0.2" }, "peerDependencies": { "semantic-release": ">=20.1.0" } }, "sha512-cXNTbv3nXR2hlzHjAMgbuiQVtvWHTlwwISt60B+4NZv01y/QRY7p2HcJm8Eh2StzcTJoNnflvKjHH/cjFS7d5g=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/error": ["@semantic-release/error@4.0.0", "", {}, "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/github": ["@semantic-release/github@9.2.6", "", { "dependencies": { "@octokit/core": "^5.0.0", "@octokit/plugin-paginate-rest": "^9.0.0", "@octokit/plugin-retry": "^6.0.0", "@octokit/plugin-throttling": "^8.0.0", "@semantic-release/error": "^4.0.0", "aggregate-error": "^5.0.0", "debug": "^4.3.4", "dir-glob": "^3.0.1", "globby": "^14.0.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", "issue-parser": "^6.0.0", "lodash-es": "^4.17.21", "mime": "^4.0.0", "p-filter": "^4.0.0", "url-join": "^5.0.0" }, "peerDependencies": { "semantic-release": ">=20.1.0" } }, "sha512-shi+Lrf6exeNZF+sBhK+P011LSbhmIAoUEgEY6SsxF8irJ+J2stwI5jkyDQ+4gzYyDImzV6LCKdYB9FXnQRWKA=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/npm": ["@semantic-release/npm@11.0.3", "", { "dependencies": { "@semantic-release/error": "^4.0.0", "aggregate-error": "^5.0.0", "execa": "^8.0.0", "fs-extra": "^11.0.0", "lodash-es": "^4.17.21", "nerf-dart": "^1.0.0", "normalize-url": "^8.0.0", "npm": "^10.5.0", "rc": "^1.2.8", "read-pkg": "^9.0.0", "registry-auth-token": "^5.0.0", "semver": "^7.1.2", "tempy": "^3.0.0" }, "peerDependencies": { "semantic-release": ">=20.1.0" } }, "sha512-KUsozQGhRBAnoVg4UMZj9ep436VEGwT536/jwSqB7vcEfA6oncCUU7UIYTRdLx7GvTtqn0kBjnkfLVkcnBa2YQ=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/release-notes-generator": ["@semantic-release/release-notes-generator@12.1.0", "", { "dependencies": { "conventional-changelog-angular": "^7.0.0", "conventional-changelog-writer": "^7.0.0", "conventional-commits-filter": "^4.0.0", "conventional-commits-parser": "^5.0.0", "debug": "^4.0.0", "get-stream": "^7.0.0", "import-from-esm": "^1.0.3", "into-stream": "^7.0.0", "lodash-es": "^4.17.21", "read-pkg-up": "^11.0.0" }, "peerDependencies": { "semantic-release": ">=20.1.0" } }, "sha512-g6M9AjUKAZUZnxaJZnouNBeDNTCUrJ5Ltj+VJ60gJeDaRRahcHsry9HW8yKrnKkKNkx5lbWiEP1FPMqVNQz8Kg=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/aggregate-error": ["aggregate-error@5.0.0", "", { "dependencies": { "clean-stack": "^5.2.0", "indent-string": "^5.0.0" } }, "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/cosmiconfig": ["cosmiconfig@8.3.6", "", { "dependencies": { "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", "parse-json": "^5.2.0", "path-type": "^4.0.0" }, "peerDependencies": { "typescript": ">=4.9.5" }, "optionalPeers": ["typescript"] }, "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/env-ci": ["env-ci@10.0.0", "", { "dependencies": { "execa": "^8.0.0", "java-properties": "^1.0.2" } }, "sha512-U4xcd/utDYFgMh0yWj07R1H6L5fwhVbmxBCpnL0DbVSDZVnsC82HONw0wxtxNkIAcua3KtbomQvIk5xFZGAQJw=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/find-versions": ["find-versions@5.1.0", "", { "dependencies": { "semver-regex": "^4.0.5" } }, "sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/hosted-git-info": ["hosted-git-info@7.0.2", "", { "dependencies": { "lru-cache": "^10.0.1" } }, "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/import-from-esm": ["import-from-esm@1.3.4", "", { "dependencies": { "debug": "^4.3.4", "import-meta-resolve": "^4.0.0" } }, "sha512-7EyUlPFC0HOlBDpUFGfYstsU7XHxZJKAAMzCT8wZ0hMW7b+hG51LIKTDcsgtz8Pu6YC0HqRVbX+rVUtsGMUKvg=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/marked": ["marked@9.1.6", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/marked-terminal": ["marked-terminal@6.3.0", "", { "dependencies": { "ansi-escapes": "^6.2.0", "chalk": "^5.3.0", "cli-highlight": "^2.1.11", "cli-table3": "^0.6.3", "node-emoji": "^2.1.3", "supports-hyperlinks": "^3.0.0" }, "peerDependencies": { "marked": ">=1 <13" } }, "sha512-icQT4cpNHOC3uxYr0DjZx8yYbFVnb40dzbvbqe9G2CRpFPnCe/RjfPXzP3xKm2vrd8sw4Sqsc3O+IsoPMzE/Iw=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/p-reduce": ["p-reduce@3.0.0", "", {}, "sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="],
+
+ "@semantic-release/commit-analyzer/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
+
+ "@semantic-release/exec/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
+
+ "@semantic-release/exec/execa/human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="],
+
+ "@semantic-release/exec/execa/is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="],
+
+ "@semantic-release/exec/execa/npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="],
+
+ "@semantic-release/exec/execa/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
+
+ "@semantic-release/exec/execa/strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="],
+
+ "@semantic-release/git/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
+
+ "@semantic-release/git/execa/human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="],
+
+ "@semantic-release/git/execa/is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="],
+
+ "@semantic-release/git/execa/npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="],
+
+ "@semantic-release/git/execa/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
+
+ "@semantic-release/git/execa/strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="],
+
+ "@semantic-release/github/aggregate-error/clean-stack": ["clean-stack@5.2.0", "", { "dependencies": { "escape-string-regexp": "5.0.0" } }, "sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ=="],
+
+ "@semantic-release/github/aggregate-error/indent-string": ["indent-string@5.0.0", "", {}, "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg=="],
+
+ "@semantic-release/github/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
+
+ "@semantic-release/npm/aggregate-error/clean-stack": ["clean-stack@5.2.0", "", { "dependencies": { "escape-string-regexp": "5.0.0" } }, "sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ=="],
+
+ "@semantic-release/npm/aggregate-error/indent-string": ["indent-string@5.0.0", "", {}, "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg=="],
+
+ "@semantic-release/npm/execa/get-stream": ["get-stream@9.0.1", "", { "dependencies": { "@sec-ant/readable-stream": "^0.4.1", "is-stream": "^4.0.1" } }, "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA=="],
+
+ "@semantic-release/npm/execa/human-signals": ["human-signals@7.0.0", "", {}, "sha512-74kytxOUSvNbjrT9KisAbaTZ/eJwD/LrbM/kh5j0IhPuJzwuA19dWvniFGwBzN9rVjg+O/e+F310PjObDXS+9Q=="],
+
+ "@semantic-release/npm/execa/npm-run-path": ["npm-run-path@5.3.0", "", { "dependencies": { "path-key": "^4.0.0" } }, "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ=="],
+
+ "@semantic-release/release-notes-generator/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
+
+ "agent-base/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
+
+ "cli-highlight/chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
+
+ "cli-highlight/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
+
+ "cli-highlight/yargs/cliui": ["cliui@7.0.4", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" } }, "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ=="],
+
+ "cli-highlight/yargs/yargs-parser": ["yargs-parser@20.2.9", "", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="],
+
+ "env-ci/execa/get-stream": ["get-stream@8.0.1", "", {}, "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA=="],
+
+ "env-ci/execa/human-signals": ["human-signals@5.0.0", "", {}, "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ=="],
+
+ "env-ci/execa/is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="],
+
+ "env-ci/execa/npm-run-path": ["npm-run-path@5.3.0", "", { "dependencies": { "path-key": "^4.0.0" } }, "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ=="],
+
+ "env-ci/execa/onetime": ["onetime@6.0.0", "", { "dependencies": { "mimic-fn": "^4.0.0" } }, "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ=="],
+
+ "env-ci/execa/strip-final-newline": ["strip-final-newline@3.0.0", "", {}, "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw=="],
+
+ "esbuild-register/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
+
+ "http-proxy-agent/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
+
+ "https-proxy-agent/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
+
+ "import-from-esm/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
+
+ "node-gyp/which/isexe": ["isexe@3.1.1", "", {}, "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="],
+
+ "npm/which/isexe": ["isexe@3.1.1", "", {}, "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="],
+
+ "semantic-release/aggregate-error/clean-stack": ["clean-stack@5.2.0", "", { "dependencies": { "escape-string-regexp": "5.0.0" } }, "sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ=="],
+
+ "semantic-release/aggregate-error/indent-string": ["indent-string@5.0.0", "", {}, "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg=="],
+
+ "semantic-release/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
+
+ "semantic-release/execa/get-stream": ["get-stream@9.0.1", "", { "dependencies": { "@sec-ant/readable-stream": "^0.4.1", "is-stream": "^4.0.1" } }, "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA=="],
+
+ "semantic-release/execa/human-signals": ["human-signals@7.0.0", "", {}, "sha512-74kytxOUSvNbjrT9KisAbaTZ/eJwD/LrbM/kh5j0IhPuJzwuA19dWvniFGwBzN9rVjg+O/e+F310PjObDXS+9Q=="],
+
+ "semantic-release/execa/npm-run-path": ["npm-run-path@5.3.0", "", { "dependencies": { "path-key": "^4.0.0" } }, "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ=="],
+
+ "socks-proxy-agent/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
+
+ "tar/fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
+
+ "tuf-js/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
+
+ "wrap-ansi-cjs/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
+
+ "wrap-ansi/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
+
+ "@commitlint/top-level/find-up/locate-path/p-locate": ["p-locate@6.0.0", "", { "dependencies": { "p-limit": "^4.0.0" } }, "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/commit-analyzer/conventional-changelog-angular": ["conventional-changelog-angular@7.0.0", "", { "dependencies": { "compare-func": "^2.0.0" } }, "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/commit-analyzer/conventional-commits-filter": ["conventional-commits-filter@4.0.0", "", {}, "sha512-rnpnibcSOdFcdclpFwWa+pPlZJhXE7l+XK04zxhbWrhgpR96h33QLz8hITTXbcYICxVr3HZFtbtUAQ+4LdBo9A=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/commit-analyzer/conventional-commits-parser": ["conventional-commits-parser@5.0.0", "", { "dependencies": { "JSONStream": "^1.3.5", "is-text-path": "^2.0.0", "meow": "^12.0.1", "split2": "^4.0.0" }, "bin": { "conventional-commits-parser": "cli.mjs" } }, "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/github/@octokit/core": ["@octokit/core@5.2.0", "", { "dependencies": { "@octokit/auth-token": "^4.0.0", "@octokit/graphql": "^7.1.0", "@octokit/request": "^8.3.1", "@octokit/request-error": "^5.1.0", "@octokit/types": "^13.0.0", "before-after-hook": "^2.2.0", "universal-user-agent": "^6.0.0" } }, "sha512-1LFfa/qnMQvEOAdzlQymH0ulepxbxnCYAKJZfMci/5XJyIHWgEYnDmgnKakbTh7CH2tFQ5O60oYDvns4i9RAIg=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/github/@octokit/plugin-paginate-rest": ["@octokit/plugin-paginate-rest@9.2.1", "", { "dependencies": { "@octokit/types": "^12.6.0" }, "peerDependencies": { "@octokit/core": "5" } }, "sha512-wfGhE/TAkXZRLjksFXuDZdmGnJQHvtU/joFQdweXUgzo1XwvBCD4o4+75NtFfjfLK5IwLf9vHTfSiU3sLRYpRw=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/github/@octokit/plugin-retry": ["@octokit/plugin-retry@6.0.1", "", { "dependencies": { "@octokit/request-error": "^5.0.0", "@octokit/types": "^12.0.0", "bottleneck": "^2.15.3" }, "peerDependencies": { "@octokit/core": ">=5" } }, "sha512-SKs+Tz9oj0g4p28qkZwl/topGcb0k0qPNX/i7vBKmDsjoeqnVfFUquqrE/O9oJY7+oLzdCtkiWSXLpLjvl6uog=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/github/@octokit/plugin-throttling": ["@octokit/plugin-throttling@8.2.0", "", { "dependencies": { "@octokit/types": "^12.2.0", "bottleneck": "^2.15.3" }, "peerDependencies": { "@octokit/core": "^5.0.0" } }, "sha512-nOpWtLayKFpgqmgD0y3GqXafMFuKcA4tRPZIfu7BArd2lEZeb1988nhWhwx4aZWmjDmUfdgVf7W+Tt4AmvRmMQ=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/github/issue-parser": ["issue-parser@6.0.0", "", { "dependencies": { "lodash.capitalize": "^4.2.1", "lodash.escaperegexp": "^4.1.2", "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.uniqby": "^4.7.0" } }, "sha512-zKa/Dxq2lGsBIXQ7CUZWTHfvxPC2ej0KfO7fIPqLlHB9J2hJ7rGhZ5rilhuufylr4RXYPzJUeFjKxz305OsNlA=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/release-notes-generator/conventional-changelog-angular": ["conventional-changelog-angular@7.0.0", "", { "dependencies": { "compare-func": "^2.0.0" } }, "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/release-notes-generator/conventional-changelog-writer": ["conventional-changelog-writer@7.0.1", "", { "dependencies": { "conventional-commits-filter": "^4.0.0", "handlebars": "^4.7.7", "json-stringify-safe": "^5.0.1", "meow": "^12.0.1", "semver": "^7.5.2", "split2": "^4.0.0" }, "bin": { "conventional-changelog-writer": "cli.mjs" } }, "sha512-Uo+R9neH3r/foIvQ0MKcsXkX642hdm9odUp7TqgFS7BsalTcjzRlIfWZrZR1gbxOozKucaKt5KAbjW8J8xRSmA=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/release-notes-generator/conventional-commits-filter": ["conventional-commits-filter@4.0.0", "", {}, "sha512-rnpnibcSOdFcdclpFwWa+pPlZJhXE7l+XK04zxhbWrhgpR96h33QLz8hITTXbcYICxVr3HZFtbtUAQ+4LdBo9A=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/release-notes-generator/conventional-commits-parser": ["conventional-commits-parser@5.0.0", "", { "dependencies": { "JSONStream": "^1.3.5", "is-text-path": "^2.0.0", "meow": "^12.0.1", "split2": "^4.0.0" }, "bin": { "conventional-commits-parser": "cli.mjs" } }, "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/release-notes-generator/get-stream": ["get-stream@7.0.1", "", {}, "sha512-3M8C1EOFN6r8AMUhwUAACIoXZJEOufDU5+0gFFN5uNs6XYOralD2Pqkl7m046va6x77FwposWXbAhPPIOus7mQ=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/aggregate-error/clean-stack": ["clean-stack@5.2.0", "", { "dependencies": { "escape-string-regexp": "5.0.0" } }, "sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/aggregate-error/indent-string": ["indent-string@5.0.0", "", {}, "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/execa/get-stream": ["get-stream@8.0.1", "", {}, "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/execa/human-signals": ["human-signals@5.0.0", "", {}, "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/execa/is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/execa/npm-run-path": ["npm-run-path@5.3.0", "", { "dependencies": { "path-key": "^4.0.0" } }, "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/execa/onetime": ["onetime@6.0.0", "", { "dependencies": { "mimic-fn": "^4.0.0" } }, "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/execa/strip-final-newline": ["strip-final-newline@3.0.0", "", {}, "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/marked-terminal/ansi-escapes": ["ansi-escapes@6.2.1", "", {}, "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/marked-terminal/chalk": ["chalk@5.3.0", "", {}, "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w=="],
+
+ "@semantic-release/github/aggregate-error/clean-stack/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
+
+ "@semantic-release/npm/aggregate-error/clean-stack/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
+
+ "@semantic-release/npm/execa/npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
+
+ "cli-highlight/chalk/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
+
+ "env-ci/execa/npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
+
+ "env-ci/execa/onetime/mimic-fn": ["mimic-fn@4.0.0", "", {}, "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw=="],
+
+ "semantic-release/aggregate-error/clean-stack/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
+
+ "semantic-release/execa/npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
+
+ "wrap-ansi-cjs/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
+
+ "wrap-ansi/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
+
+ "@commitlint/top-level/find-up/locate-path/p-locate/p-limit": ["p-limit@4.0.0", "", { "dependencies": { "yocto-queue": "^1.0.0" } }, "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/commit-analyzer/conventional-commits-parser/split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/github/@octokit/core/@octokit/auth-token": ["@octokit/auth-token@4.0.0", "", {}, "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/github/@octokit/core/@octokit/graphql": ["@octokit/graphql@7.1.0", "", { "dependencies": { "@octokit/request": "^8.3.0", "@octokit/types": "^13.0.0", "universal-user-agent": "^6.0.0" } }, "sha512-r+oZUH7aMFui1ypZnAvZmn0KSqAUgE1/tUXIWaqUCa1758ts/Jio84GZuzsvUkme98kv0WFY8//n0J1Z+vsIsQ=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/github/@octokit/core/@octokit/request": ["@octokit/request@8.4.0", "", { "dependencies": { "@octokit/endpoint": "^9.0.1", "@octokit/request-error": "^5.1.0", "@octokit/types": "^13.1.0", "universal-user-agent": "^6.0.0" } }, "sha512-9Bb014e+m2TgBeEJGEbdplMVWwPmL1FPtggHQRkV+WVsMggPtEkLKPlcVYm/o8xKLkpJ7B+6N8WfQMtDLX2Dpw=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/github/@octokit/core/@octokit/request-error": ["@octokit/request-error@5.1.0", "", { "dependencies": { "@octokit/types": "^13.1.0", "deprecation": "^2.0.0", "once": "^1.4.0" } }, "sha512-GETXfE05J0+7H2STzekpKObFe765O5dlAKUTLNGeH+x47z7JjXHfsHKo5z21D/o/IOZTUEI6nyWyR+bZVP/n5Q=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/github/@octokit/core/before-after-hook": ["before-after-hook@2.2.3", "", {}, "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/github/@octokit/core/universal-user-agent": ["universal-user-agent@6.0.1", "", {}, "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/github/@octokit/plugin-paginate-rest/@octokit/types": ["@octokit/types@12.6.0", "", { "dependencies": { "@octokit/openapi-types": "^20.0.0" } }, "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/github/@octokit/plugin-retry/@octokit/request-error": ["@octokit/request-error@5.1.0", "", { "dependencies": { "@octokit/types": "^13.1.0", "deprecation": "^2.0.0", "once": "^1.4.0" } }, "sha512-GETXfE05J0+7H2STzekpKObFe765O5dlAKUTLNGeH+x47z7JjXHfsHKo5z21D/o/IOZTUEI6nyWyR+bZVP/n5Q=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/github/@octokit/plugin-retry/@octokit/types": ["@octokit/types@12.6.0", "", { "dependencies": { "@octokit/openapi-types": "^20.0.0" } }, "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/github/@octokit/plugin-throttling/@octokit/types": ["@octokit/types@12.6.0", "", { "dependencies": { "@octokit/openapi-types": "^20.0.0" } }, "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/release-notes-generator/conventional-changelog-writer/split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/release-notes-generator/conventional-commits-parser/split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/aggregate-error/clean-stack/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/execa/npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/execa/onetime/mimic-fn": ["mimic-fn@4.0.0", "", {}, "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw=="],
+
+ "cli-highlight/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/github/@octokit/core/@octokit/request/@octokit/endpoint": ["@octokit/endpoint@9.0.5", "", { "dependencies": { "@octokit/types": "^13.1.0", "universal-user-agent": "^6.0.0" } }, "sha512-ekqR4/+PCLkEBF6qgj8WqJfvDq65RH85OAgrtnVp1mSxaXF03u2xW/hUdweGS5654IlC0wkNYC18Z50tSYTAFw=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/github/@octokit/plugin-paginate-rest/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@20.0.0", "", {}, "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/github/@octokit/plugin-retry/@octokit/request-error/@octokit/types": ["@octokit/types@13.5.0", "", { "dependencies": { "@octokit/openapi-types": "^22.2.0" } }, "sha512-HdqWTf5Z3qwDVlzCrP8UJquMwunpDiMPt5er+QjGzL4hqr/vBVY/MauQgS1xWxCDT1oMx1EULyqxncdCY/NVSQ=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/github/@octokit/plugin-retry/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@20.0.0", "", {}, "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA=="],
+
+ "@saithodev/semantic-release-backmerge/semantic-release/@semantic-release/github/@octokit/plugin-throttling/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@20.0.0", "", {}, "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA=="],
+ }
+}
diff --git a/bunfig.toml b/bunfig.toml
new file mode 100644
index 0000000..4bc324e
--- /dev/null
+++ b/bunfig.toml
@@ -0,0 +1,2 @@
+smol = true
+telemetry = false
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
deleted file mode 100644
index 338dbf3..0000000
--- a/docker-compose.yml
+++ /dev/null
@@ -1,15 +0,0 @@
-version: '3.8'
-
-services:
- revanced-helper:
- container_name: revanced-helper
- image: ghcr.io/revanced/revanced-helper:latest
- # Required because otherwise failing with ECONNREFUSED
- network_mode: "host"
- environment:
- - WIT_AI_TOKEN=YOUR_WIT_AI_TOKEN
- - MONGODB_URI=YOUR_MONGODB_URI
- - DISCORD_TOKEN=YOUR_DISCORD_TOKEN
- volumes:
- - /data/revanced-helper/discord-bot-config.json:/usr/src/revanced-helper/apps/bot-discord/src/config.json
- - /data/revanced-helper/server-config.json:/usr/src/revanced-helper/apps/server/src/config.json
diff --git a/docs/0_development_environment.md b/docs/0_development_environment.md
new file mode 100644
index 0000000..15784bf
--- /dev/null
+++ b/docs/0_development_environment.md
@@ -0,0 +1,53 @@
+# 🏗️ Setting up the development environment
+
+> [!IMPORTANT]
+> **This project uses [Bun](https://bun.sh) to run and bundle the code.**
+> Compatibility with other runtimes (Node.js, Deno, ...) are not guaranteed and most package scripts won't work.
+
+To start developing, you'll need to set up the development environment first.
+
+1. Install [Bun](https://bun.sh)
+
+2. Clone the mono-repository
+
+ ```sh
+ git clone https://github.com/revanced/revanced-bots.git &&
+ cd revanced-bots
+ ```
+
+3. Install dependencies
+
+ ```sh
+ bun install
+ ```
+
+4. Install Git hooks for linting (optional, but recommended)
+
+ ```sh
+ bunx lefthook install
+ ```
+
+5. Build packages/libraries
+
+ ```sh
+ bun run build:packages
+ ```
+
+6. Change your directory to a project's root
+
+ ```sh
+ # WebSocket API
+ cd apis/websocket
+
+ # Discord bot
+ cd bots/discord
+
+ # Programmatic API
+ cd packages/api
+
+ # Etc.
+ ```
+
+## ⏭️ What's next
+
+You'll need to go to the respective project's documentation to continue.
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 0000000..d53d4de
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,13 @@
+# 🚙 ReVanced Bot
+
+This documentation are steps required to start developing ReVanced bots.
+
+## 📖 Table of contents
+
+0. [🏗️ Setting up the development environment](./0_development_environment.md)
+
+## ⏭️ Start here
+
+The next page will tell you how to set up the development environment.
+
+Continue: [🏗️ Setting up the development environment](./0_development_environment.md)
diff --git a/lefthook.yml b/lefthook.yml
new file mode 100755
index 0000000..c2581aa
--- /dev/null
+++ b/lefthook.yml
@@ -0,0 +1,12 @@
+pre-commit:
+ parallel: true
+ commands:
+ check:
+ files: git diff --name-only --cached --diff-filter=AM @{push}
+ glob: "*.{js,ts,json}"
+ run: bunx biome check {files}
+commit-msg:
+ parallel: false
+ commands:
+ commitlint:
+ run: bunx commitlint --edit
diff --git a/package-lock.json b/package-lock.json
deleted file mode 100644
index e2ee3db..0000000
--- a/package-lock.json
+++ /dev/null
@@ -1,1939 +0,0 @@
-{
- "name": "revanced-helper",
- "version": "0.0.1",
- "lockfileVersion": 2,
- "requires": true,
- "packages": {
- "": {
- "name": "revanced-helper",
- "version": "0.0.1",
- "license": "GPL-3.0-or-later",
- "devDependencies": {
- "eslint": "^8.27.0",
- "prettier": "2.7.1"
- }
- },
- "node_modules/@eslint/eslintrc": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz",
- "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==",
- "dev": true,
- "dependencies": {
- "ajv": "^6.12.4",
- "debug": "^4.3.2",
- "espree": "^9.4.0",
- "globals": "^13.15.0",
- "ignore": "^5.2.0",
- "import-fresh": "^3.2.1",
- "js-yaml": "^4.1.0",
- "minimatch": "^3.1.2",
- "strip-json-comments": "^3.1.1"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/@humanwhocodes/config-array": {
- "version": "0.11.7",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz",
- "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==",
- "dev": true,
- "dependencies": {
- "@humanwhocodes/object-schema": "^1.2.1",
- "debug": "^4.1.1",
- "minimatch": "^3.0.5"
- },
- "engines": {
- "node": ">=10.10.0"
- }
- },
- "node_modules/@humanwhocodes/module-importer": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
- "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
- "dev": true,
- "engines": {
- "node": ">=12.22"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/nzakas"
- }
- },
- "node_modules/@humanwhocodes/object-schema": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
- "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
- "dev": true
- },
- "node_modules/@nodelib/fs.scandir": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
- "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
- "dev": true,
- "dependencies": {
- "@nodelib/fs.stat": "2.0.5",
- "run-parallel": "^1.1.9"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@nodelib/fs.stat": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
- "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
- "dev": true,
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@nodelib/fs.walk": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
- "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
- "dev": true,
- "dependencies": {
- "@nodelib/fs.scandir": "2.1.5",
- "fastq": "^1.6.0"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/acorn": {
- "version": "8.8.1",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
- "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==",
- "dev": true,
- "bin": {
- "acorn": "bin/acorn"
- },
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/acorn-jsx": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
- "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
- "dev": true,
- "peerDependencies": {
- "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
- }
- },
- "node_modules/ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "dev": true,
- "dependencies": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/epoberezkin"
- }
- },
- "node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/argparse": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "dev": true
- },
- "node_modules/balanced-match": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
- "dev": true
- },
- "node_modules/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/callsites": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
- "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
- "dev": true
- },
- "node_modules/cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "dev": true,
- "dependencies": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "dev": true,
- "dependencies": {
- "ms": "2.1.2"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/deep-is": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
- "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
- "dev": true
- },
- "node_modules/doctrine": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
- "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
- "dev": true,
- "dependencies": {
- "esutils": "^2.0.2"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/escape-string-regexp": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
- "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/eslint": {
- "version": "8.27.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.27.0.tgz",
- "integrity": "sha512-0y1bfG2ho7mty+SiILVf9PfuRA49ek4Nc60Wmmu62QlobNR+CeXa4xXIJgcuwSQgZiWaPH+5BDsctpIW0PR/wQ==",
- "dev": true,
- "dependencies": {
- "@eslint/eslintrc": "^1.3.3",
- "@humanwhocodes/config-array": "^0.11.6",
- "@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.15.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/eslint-scope": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
- "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
- "dev": true,
- "dependencies": {
- "esrecurse": "^4.3.0",
- "estraverse": "^5.2.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- }
- },
- "node_modules/eslint-utils": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
- "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
- "dev": true,
- "dependencies": {
- "eslint-visitor-keys": "^2.0.0"
- },
- "engines": {
- "node": "^10.0.0 || ^12.0.0 || >= 14.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/mysticatea"
- },
- "peerDependencies": {
- "eslint": ">=5"
- }
- },
- "node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
- "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
- "dev": true,
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/eslint-visitor-keys": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
- "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
- "dev": true,
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- }
- },
- "node_modules/espree": {
- "version": "9.4.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz",
- "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==",
- "dev": true,
- "dependencies": {
- "acorn": "^8.8.0",
- "acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^3.3.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/esquery": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
- "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
- "dev": true,
- "dependencies": {
- "estraverse": "^5.1.0"
- },
- "engines": {
- "node": ">=0.10"
- }
- },
- "node_modules/esrecurse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
- "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
- "dev": true,
- "dependencies": {
- "estraverse": "^5.2.0"
- },
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
- "dev": true,
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/esutils": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
- "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/fast-deep-equal": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true
- },
- "node_modules/fast-json-stable-stringify": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
- "dev": true
- },
- "node_modules/fast-levenshtein": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
- "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
- "dev": true
- },
- "node_modules/fastq": {
- "version": "1.13.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
- "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
- "dev": true,
- "dependencies": {
- "reusify": "^1.0.4"
- }
- },
- "node_modules/file-entry-cache": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
- "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
- "dev": true,
- "dependencies": {
- "flat-cache": "^3.0.4"
- },
- "engines": {
- "node": "^10.12.0 || >=12.0.0"
- }
- },
- "node_modules/find-up": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
- "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
- "dev": true,
- "dependencies": {
- "locate-path": "^6.0.0",
- "path-exists": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/flat-cache": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
- "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
- "dev": true,
- "dependencies": {
- "flatted": "^3.1.0",
- "rimraf": "^3.0.2"
- },
- "engines": {
- "node": "^10.12.0 || >=12.0.0"
- }
- },
- "node_modules/flatted": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
- "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
- "dev": true
- },
- "node_modules/fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
- "dev": true
- },
- "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/glob-parent": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
- "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
- "dev": true,
- "dependencies": {
- "is-glob": "^4.0.3"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/globals": {
- "version": "13.17.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
- "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
- "dev": true,
- "dependencies": {
- "type-fest": "^0.20.2"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/grapheme-splitter": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
- "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
- "dev": true
- },
- "node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/ignore": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
- "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
- "dev": true,
- "engines": {
- "node": ">= 4"
- }
- },
- "node_modules/import-fresh": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
- "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
- "dev": true,
- "dependencies": {
- "parent-module": "^1.0.0",
- "resolve-from": "^4.0.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/imurmurhash": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
- "dev": true,
- "engines": {
- "node": ">=0.8.19"
- }
- },
- "node_modules/inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
- "dev": true,
- "dependencies": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "node_modules/inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
- "dev": true
- },
- "node_modules/is-extglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-glob": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
- "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "dev": true,
- "dependencies": {
- "is-extglob": "^2.1.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-path-inside": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
- "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/isexe": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
- "dev": true
- },
- "node_modules/js-sdsl": {
- "version": "4.1.5",
- "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz",
- "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==",
- "dev": true
- },
- "node_modules/js-yaml": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
- "dev": true,
- "dependencies": {
- "argparse": "^2.0.1"
- },
- "bin": {
- "js-yaml": "bin/js-yaml.js"
- }
- },
- "node_modules/json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true
- },
- "node_modules/json-stable-stringify-without-jsonify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
- "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
- "dev": true
- },
- "node_modules/levn": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
- "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
- "dev": true,
- "dependencies": {
- "prelude-ls": "^1.2.1",
- "type-check": "~0.4.0"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/locate-path": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
- "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
- "dev": true,
- "dependencies": {
- "p-locate": "^5.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/lodash.merge": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
- "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
- "dev": true
- },
- "node_modules/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/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- },
- "node_modules/natural-compare": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
- "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
- "dev": true
- },
- "node_modules/once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
- "dev": true,
- "dependencies": {
- "wrappy": "1"
- }
- },
- "node_modules/optionator": {
- "version": "0.9.1",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
- "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
- "dev": true,
- "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",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "dependencies": {
- "yocto-queue": "^0.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/p-locate": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
- "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
- "dev": true,
- "dependencies": {
- "p-limit": "^3.0.2"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/parent-module": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
- "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
- "dev": true,
- "dependencies": {
- "callsites": "^3.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/path-key": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/prelude-ls": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
- "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
- "dev": true,
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/prettier": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
- "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
- "dev": true,
- "bin": {
- "prettier": "bin-prettier.js"
- },
- "engines": {
- "node": ">=10.13.0"
- },
- "funding": {
- "url": "https://github.com/prettier/prettier?sponsor=1"
- }
- },
- "node_modules/punycode": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
- "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/queue-microtask": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
- "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ]
- },
- "node_modules/regexpp": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
- "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
- "dev": true,
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/mysticatea"
- }
- },
- "node_modules/resolve-from": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
- "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/reusify": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
- "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
- "dev": true,
- "engines": {
- "iojs": ">=1.0.0",
- "node": ">=0.10.0"
- }
- },
- "node_modules/rimraf": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
- "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
- "dev": true,
- "dependencies": {
- "glob": "^7.1.3"
- },
- "bin": {
- "rimraf": "bin.js"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/run-parallel": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
- "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "dependencies": {
- "queue-microtask": "^1.2.2"
- }
- },
- "node_modules/shebang-command": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "dev": true,
- "dependencies": {
- "shebang-regex": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/shebang-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "dependencies": {
- "ansi-regex": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/strip-json-comments": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
- "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
- "dev": true,
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/text-table": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
- "dev": true
- },
- "node_modules/type-check": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
- "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
- "dev": true,
- "dependencies": {
- "prelude-ls": "^1.2.1"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/type-fest": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
- "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/uri-js": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
- "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "dev": true,
- "dependencies": {
- "punycode": "^2.1.0"
- }
- },
- "node_modules/which": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
- "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "dev": true,
- "dependencies": {
- "isexe": "^2.0.0"
- },
- "bin": {
- "node-which": "bin/node-which"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/word-wrap": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
- "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
- "dev": true
- },
- "node_modules/yocto-queue": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
- "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- }
- },
- "dependencies": {
- "@eslint/eslintrc": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz",
- "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==",
- "dev": true,
- "requires": {
- "ajv": "^6.12.4",
- "debug": "^4.3.2",
- "espree": "^9.4.0",
- "globals": "^13.15.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"
- }
- },
- "@humanwhocodes/config-array": {
- "version": "0.11.7",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz",
- "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==",
- "dev": true,
- "requires": {
- "@humanwhocodes/object-schema": "^1.2.1",
- "debug": "^4.1.1",
- "minimatch": "^3.0.5"
- }
- },
- "@humanwhocodes/module-importer": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
- "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
- "dev": true
- },
- "@humanwhocodes/object-schema": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
- "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
- "dev": true
- },
- "@nodelib/fs.scandir": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
- "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
- "dev": true,
- "requires": {
- "@nodelib/fs.stat": "2.0.5",
- "run-parallel": "^1.1.9"
- }
- },
- "@nodelib/fs.stat": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
- "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
- "dev": true
- },
- "@nodelib/fs.walk": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
- "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
- "dev": true,
- "requires": {
- "@nodelib/fs.scandir": "2.1.5",
- "fastq": "^1.6.0"
- }
- },
- "acorn": {
- "version": "8.8.1",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
- "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==",
- "dev": true
- },
- "acorn-jsx": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
- "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
- "dev": true,
- "requires": {}
- },
- "ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "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-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true
- },
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "argparse": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "dev": true
- },
- "balanced-match": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
- "dev": true
- },
- "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"
- }
- },
- "callsites": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
- "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
- "dev": true
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
- "dev": true
- },
- "cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "dev": true,
- "requires": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- }
- },
- "debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "dev": true,
- "requires": {
- "ms": "2.1.2"
- }
- },
- "deep-is": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
- "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
- "dev": true
- },
- "doctrine": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
- "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
- "dev": true,
- "requires": {
- "esutils": "^2.0.2"
- }
- },
- "escape-string-regexp": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
- "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
- "dev": true
- },
- "eslint": {
- "version": "8.27.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.27.0.tgz",
- "integrity": "sha512-0y1bfG2ho7mty+SiILVf9PfuRA49ek4Nc60Wmmu62QlobNR+CeXa4xXIJgcuwSQgZiWaPH+5BDsctpIW0PR/wQ==",
- "dev": true,
- "requires": {
- "@eslint/eslintrc": "^1.3.3",
- "@humanwhocodes/config-array": "^0.11.6",
- "@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.15.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"
- }
- },
- "eslint-scope": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
- "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
- "dev": true,
- "requires": {
- "esrecurse": "^4.3.0",
- "estraverse": "^5.2.0"
- }
- },
- "eslint-utils": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
- "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
- "dev": true,
- "requires": {
- "eslint-visitor-keys": "^2.0.0"
- },
- "dependencies": {
- "eslint-visitor-keys": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
- "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
- "dev": true
- }
- }
- },
- "eslint-visitor-keys": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
- "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
- "dev": true
- },
- "espree": {
- "version": "9.4.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz",
- "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==",
- "dev": true,
- "requires": {
- "acorn": "^8.8.0",
- "acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^3.3.0"
- }
- },
- "esquery": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
- "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
- "dev": true,
- "requires": {
- "estraverse": "^5.1.0"
- }
- },
- "esrecurse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
- "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
- "dev": true,
- "requires": {
- "estraverse": "^5.2.0"
- }
- },
- "estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
- "dev": true
- },
- "esutils": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
- "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
- "dev": true
- },
- "fast-deep-equal": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true
- },
- "fast-json-stable-stringify": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
- "dev": true
- },
- "fast-levenshtein": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
- "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
- "dev": true
- },
- "fastq": {
- "version": "1.13.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
- "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
- "dev": true,
- "requires": {
- "reusify": "^1.0.4"
- }
- },
- "file-entry-cache": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
- "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
- "dev": true,
- "requires": {
- "flat-cache": "^3.0.4"
- }
- },
- "find-up": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
- "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
- "dev": true,
- "requires": {
- "locate-path": "^6.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "flat-cache": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
- "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
- "dev": true,
- "requires": {
- "flatted": "^3.1.0",
- "rimraf": "^3.0.2"
- }
- },
- "flatted": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
- "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
- "dev": true
- },
- "fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
- "dev": true
- },
- "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"
- }
- },
- "glob-parent": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
- "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
- "dev": true,
- "requires": {
- "is-glob": "^4.0.3"
- }
- },
- "globals": {
- "version": "13.17.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
- "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
- "dev": true,
- "requires": {
- "type-fest": "^0.20.2"
- }
- },
- "grapheme-splitter": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
- "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "ignore": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
- "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
- "dev": true
- },
- "import-fresh": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
- "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
- "dev": true,
- "requires": {
- "parent-module": "^1.0.0",
- "resolve-from": "^4.0.0"
- }
- },
- "imurmurhash": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
- "dev": true
- },
- "inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
- "dev": true,
- "requires": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
- "dev": true
- },
- "is-extglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
- "dev": true
- },
- "is-glob": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
- "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "dev": true,
- "requires": {
- "is-extglob": "^2.1.1"
- }
- },
- "is-path-inside": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
- "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
- "dev": true
- },
- "isexe": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
- "dev": true
- },
- "js-sdsl": {
- "version": "4.1.5",
- "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz",
- "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==",
- "dev": true
- },
- "js-yaml": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
- "dev": true,
- "requires": {
- "argparse": "^2.0.1"
- }
- },
- "json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true
- },
- "json-stable-stringify-without-jsonify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
- "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
- "dev": true
- },
- "levn": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
- "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
- "dev": true,
- "requires": {
- "prelude-ls": "^1.2.1",
- "type-check": "~0.4.0"
- }
- },
- "locate-path": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
- "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
- "dev": true,
- "requires": {
- "p-locate": "^5.0.0"
- }
- },
- "lodash.merge": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
- "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
- "dev": true
- },
- "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"
- }
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- },
- "natural-compare": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
- "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
- "dev": true
- },
- "once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
- "dev": true,
- "requires": {
- "wrappy": "1"
- }
- },
- "optionator": {
- "version": "0.9.1",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
- "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
- "dev": true,
- "requires": {
- "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"
- }
- },
- "p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "requires": {
- "yocto-queue": "^0.1.0"
- }
- },
- "p-locate": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
- "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
- "dev": true,
- "requires": {
- "p-limit": "^3.0.2"
- }
- },
- "parent-module": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
- "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
- "dev": true,
- "requires": {
- "callsites": "^3.0.0"
- }
- },
- "path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
- "dev": true
- },
- "path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
- "dev": true
- },
- "path-key": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "dev": true
- },
- "prelude-ls": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
- "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
- "dev": true
- },
- "prettier": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
- "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
- "dev": true
- },
- "punycode": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
- "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
- "dev": true
- },
- "queue-microtask": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
- "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
- "dev": true
- },
- "regexpp": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
- "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
- "dev": true
- },
- "resolve-from": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
- "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
- "dev": true
- },
- "reusify": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
- "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
- "dev": true
- },
- "rimraf": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
- "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
- "dev": true,
- "requires": {
- "glob": "^7.1.3"
- }
- },
- "run-parallel": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
- "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
- "dev": true,
- "requires": {
- "queue-microtask": "^1.2.2"
- }
- },
- "shebang-command": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "dev": true,
- "requires": {
- "shebang-regex": "^3.0.0"
- }
- },
- "shebang-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "dev": true
- },
- "strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- }
- },
- "strip-json-comments": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
- "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- },
- "text-table": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
- "dev": true
- },
- "type-check": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
- "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
- "dev": true,
- "requires": {
- "prelude-ls": "^1.2.1"
- }
- },
- "type-fest": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
- "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
- "dev": true
- },
- "uri-js": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
- "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "dev": true,
- "requires": {
- "punycode": "^2.1.0"
- }
- },
- "which": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
- "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "dev": true,
- "requires": {
- "isexe": "^2.0.0"
- }
- },
- "word-wrap": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
- "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==",
- "dev": true
- },
- "wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
- "dev": true
- },
- "yocto-queue": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
- "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
- "dev": true
- }
- }
-}
diff --git a/package.json b/package.json
index 4b40891..774699c 100644
--- a/package.json
+++ b/package.json
@@ -1,23 +1,61 @@
{
- "name": "revanced-helper",
- "version": "0.0.1",
- "description": "The community bots (and the server) to help the community and make moderators job easy.",
+ "name": "revanced-bots",
+ "description": "🤖 Bots assisting ReVanced on multiple platforms",
+ "private": true,
+ "version": "0.0.0",
+ "license": "GPL-3.0-or-later",
+ "type": "module",
+ "author": "Palm (https://palmdevs.me)",
+ "workspaces": ["packages/*", "apis/*", "bots/*"],
+ "scripts": {
+ "build:all": "turbo run build",
+ "build:packages": "turbo build --filter=\"./packages/*\"",
+ "watch": "turbo run watch",
+ "flint": "biome check --write .",
+ "flint:check": "biome check .",
+ "clint": "commitlint --edit"
+ },
+ "homepage": "https://github.com/revanced/revanced-bots#readme",
"repository": {
"type": "git",
- "url": "git+https://github.com/reisxd/revanced-helper.git"
+ "url": "git+https://github.com/revanced/revanced-bots.git"
},
- "author": "Reis Can",
- "license": "GPL-3.0-or-later",
"bugs": {
- "url": "https://github.com/reisxd/revanced-helper/issues"
- },
- "homepage": "https://github.com/reisxd/revanced-helper#readme",
- "scripts": {
- "lint": "prettier --write . && eslint --fix .",
- "start": "cd apps/server/src && (node . &) && cd ../../bot-discord/src && (node .)"
+ "url": "https://github.com/revanced/revanced-bots/issues"
},
+ "contributors": [
+ "Palm (https://palmdevs.me)",
+ "ReVanced (https://revanced.app)"
+ ],
+ "packageManager": "bun@1.1.20",
"devDependencies": {
- "eslint": "^8.27.0",
- "prettier": "2.7.1"
+ "@anolilab/multi-semantic-release": "^1.1.10",
+ "@biomejs/biome": "^1.9.4",
+ "@codedependant/semantic-release-docker": "^5.1.0",
+ "@commitlint/cli": "^19.8.0",
+ "@commitlint/config-conventional": "^19.8.0",
+ "@saithodev/semantic-release-backmerge": "^4.0.1",
+ "@semantic-release/changelog": "^6.0.3",
+ "@semantic-release/exec": "^6.0.3",
+ "@semantic-release/git": "^10.0.1",
+ "@tsconfig/strictest": "^2.0.5",
+ "@types/bun": "^1.2.8",
+ "conventional-changelog-conventionalcommits": "^7.0.2",
+ "lefthook": "^1.11.6",
+ "portainer-service-webhook": "https://github.com/newarifrh/portainer-service-webhook#v1",
+ "semantic-release": "^24.2.3",
+ "turbo": "^2.5.0",
+ "typescript": "^5.8.2"
+ },
+ "trustedDependencies": [
+ "@biomejs/biome",
+ "@revanced/discord-bot",
+ "esbuild",
+ "lefthook"
+ ],
+ "patchedDependencies": {
+ "@semantic-release/npm@12.0.1": "patches/@semantic-release%2Fnpm@12.0.1.patch",
+ "drizzle-kit@0.22.8": "patches/drizzle-kit@0.22.8.patch",
+ "decancer@3.2.4": "patches/decancer@3.2.4.patch"
}
-}
\ No newline at end of file
+}
diff --git a/packages/api/LICENSE b/packages/api/LICENSE
new file mode 100755
index 0000000..f288702
--- /dev/null
+++ b/packages/api/LICENSE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/packages/api/package.json b/packages/api/package.json
new file mode 100755
index 0000000..b4a85d7
--- /dev/null
+++ b/packages/api/package.json
@@ -0,0 +1,37 @@
+{
+ "name": "@revanced/bot-api",
+ "type": "module",
+ "version": "0.1.0",
+ "description": "🙌🏻 Programmatic API for bots assisting ReVanced to communicate to its API server",
+ "main": "dist/index.js",
+ "types": "dist/index.d.ts",
+ "scripts": {
+ "build": "bun bundle && bun types",
+ "bundle": "bun build src/index.ts --outdir=dist --target=bun",
+ "types": "tsc --declaration --emitDeclarationOnly",
+ "types:clean": "bun types --build --clean"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/revanced/revanced-bots.git",
+ "directory": "packages/api"
+ },
+ "author": "Palm (https://palmdevs.me)",
+ "contributors": [
+ "Palm (https://palmdevs.me)",
+ "ReVanced (https://revanced.app)"
+ ],
+ "license": "GPL-3.0-or-later",
+ "bugs": {
+ "url": "https://github.com/revanced/revanced-bots/issues"
+ },
+ "homepage": "https://github.com/revanced/revanced-bots#readme",
+ "dependencies": {
+ "@revanced/bot-shared": "workspace:*",
+ "ws": "^8.18.1"
+ },
+ "devDependencies": {
+ "@types/ws": "^8.18.1",
+ "typed-emitter": "^2.1.0"
+ }
+}
diff --git a/packages/api/src/classes/Client.ts b/packages/api/src/classes/Client.ts
new file mode 100755
index 0000000..333651a
--- /dev/null
+++ b/packages/api/src/classes/Client.ts
@@ -0,0 +1,235 @@
+import { ClientOperation, type Packet, ServerOperation } from '@revanced/bot-shared'
+import {
+ type ClientWebSocketEvents,
+ ClientWebSocketManager,
+ type ClientWebSocketManagerOptions,
+} from './ClientWebSocket'
+
+/**
+ * The client that connects to the API.
+ */
+export default class Client {
+ ready = false
+ ws: ClientWebSocketManager
+ #awaiter: ClientWebSocketPacketAwaiter
+
+ constructor(options: ClientOptions) {
+ this.ws = new ClientWebSocketManager(options.api.websocket)
+ this.ws.on('ready', () => {
+ this.ready = true
+ })
+ this.ws.on('disconnect', () => {
+ this.ready = false
+ })
+
+ this.#awaiter = new ClientWebSocketPacketAwaiter(this.ws)
+ }
+
+ /**
+ * Checks whether the client is ready
+ * @returns Whether the client is ready
+ */
+ isReady(): this is ReadiedClient {
+ return this.ready
+ }
+
+ /**
+ * Requests the API to parse the given text
+ * @param text The text to parse
+ * @returns An object containing the ID of the request and the labels
+ */
+ async parseText(text: string) {
+ this.#throwIfNotReady()
+
+ this.ws.send({
+ op: ClientOperation.ParseText,
+ d: {
+ text,
+ },
+ })
+
+ // Since we don't have heartbeats anymore, this is fine.
+ // But if we add anything similar, this will cause another race condition
+ // To fix this, we can try adding a instanced function that would return the currentSequence
+ // and it would be updated every time a "heartbeat ack" packet is received
+ const packet = await Promise.race([
+ this.#awaiter.await(ServerOperation.ParsedText, this.ws.currentSequence),
+ this.#awaiter.await(ServerOperation.ParseTextFailed, this.ws.currentSequence, this.ws.timeout + 5000),
+ ])
+ .then(pkt => {
+ if (pkt.op === ServerOperation.ParsedText) return pkt.d
+ return null
+ })
+ .catch(() => {
+ throw new Error('Failed to parse text, the API did not respond in time')
+ })
+
+ if (!packet) throw new Error('Failed to parse text, the API encountered an error')
+ return packet
+ }
+
+ /**
+ * Requests the API to parse the given image and return the text
+ * @param url The URL of the image
+ * @returns An object containing the ID of the request and the parsed text
+ */
+ async parseImage(url: string) {
+ this.#throwIfNotReady()
+
+ this.ws.send({
+ op: ClientOperation.ParseImage,
+ d: {
+ image_url: url,
+ },
+ })
+
+ // See line 50
+
+ const packet = await Promise.race([
+ this.#awaiter.await(ServerOperation.ParsedImage, this.ws.currentSequence),
+ this.#awaiter.await(ServerOperation.ParseImageFailed, this.ws.currentSequence, this.ws.timeout + 5000),
+ ])
+ .then(pkt => {
+ if (pkt.op === ServerOperation.ParsedImage) return pkt.d
+ return null
+ })
+ .catch(() => {
+ throw new Error('Failed to parse image, the API did not respond in time')
+ })
+
+ if (!packet) throw new Error('Failed to parse image, the API encountered an error')
+ return packet
+ }
+
+ async trainMessage(text: string, label: string) {
+ this.#throwIfNotReady()
+
+ this.ws.send({
+ op: ClientOperation.TrainMessage,
+ d: {
+ label,
+ text,
+ },
+ })
+
+ // See line 50
+ const packet = await Promise.race([
+ this.#awaiter.await(ServerOperation.TrainedMessage, this.ws.currentSequence),
+ this.#awaiter.await(ServerOperation.TrainMessageFailed, this.ws.currentSequence, this.ws.timeout + 5000),
+ ])
+ .then(pkt => {
+ if (pkt.op === ServerOperation.TrainedMessage) return pkt.d
+ return null
+ })
+ .catch(() => {
+ throw new Error('Failed to train message, the API did not respond in time')
+ })
+
+ if (!packet) throw new Error('Failed to train message, the API encountered an error')
+ return packet
+ }
+
+ /**
+ * Adds an event listener
+ * @param name The event name to listen for
+ * @param handler The event handler
+ * @returns The event handler function
+ */
+ on(name: TOpName, handler: ClientWebSocketEvents[TOpName]) {
+ this.ws.on(name, handler)
+ return handler
+ }
+
+ /**
+ * Removes an event listener
+ * @param name The event name to remove a listener from
+ * @param handler The event handler to remove
+ * @returns The removed event handler function
+ */
+ off(name: TOpName, handler: ClientWebSocketEvents[TOpName]) {
+ this.ws.off(name, handler)
+ return handler
+ }
+
+ /**
+ * Adds an event listener that will only be called once
+ * @param name The event name to listen for
+ * @param handler The event handler
+ * @returns The event handler function
+ */
+ once(name: TOpName, handler: ClientWebSocketEvents[TOpName]) {
+ this.ws.once(name, handler)
+ return handler
+ }
+
+ /**
+ * Connects the client to the API
+ */
+ connect() {
+ return this.ws.connect()
+ }
+
+ /**
+ * Disconnects the client from the API
+ */
+ disconnect(force?: boolean) {
+ this.ws.disconnect(force)
+ }
+
+ #throwIfNotReady() {
+ if (!this.isReady()) throw new Error('Client is not ready')
+ }
+
+ get disconnected() {
+ return this.ws.disconnected
+ }
+}
+
+export class ClientWebSocketPacketAwaiter {
+ #ws: ClientWebSocketManager
+ #resolvers: Map) => void>
+
+ constructor(ws: ClientWebSocketManager) {
+ this.#ws = ws
+ this.#resolvers = new Map()
+
+ this.#ws.on('packet', packet => {
+ const key = this.keyFor(packet.op, packet.s)
+ const resolve = this.#resolvers.get(key)
+ if (resolve) {
+ resolve(packet)
+ this.#resolvers.delete(key)
+ }
+ })
+ }
+
+ keyFor(op: ServerOperation, seq: number) {
+ return `${op}-${seq}`
+ }
+
+ await(
+ op: TOp,
+ expectedSeq: number,
+ timeout = 10000,
+ ): Promise> {
+ return new Promise((resolve, reject) => {
+ const key = this.keyFor(op, expectedSeq)
+ this.#resolvers.set(key, resolve)
+
+ setTimeout(() => {
+ this.#resolvers.delete(key)
+ reject('Awaiting packet timed out')
+ }, timeout)
+ })
+ }
+}
+
+export type ReadiedClient = Client & { ready: true }
+
+export interface ClientOptions {
+ api: ClientApiOptions
+}
+
+export interface ClientApiOptions {
+ websocket: ClientWebSocketManagerOptions
+}
diff --git a/packages/api/src/classes/ClientWebSocket.ts b/packages/api/src/classes/ClientWebSocket.ts
new file mode 100755
index 0000000..e4c55d9
--- /dev/null
+++ b/packages/api/src/classes/ClientWebSocket.ts
@@ -0,0 +1,242 @@
+import { EventEmitter } from 'events'
+import {
+ type ClientOperation,
+ DisconnectReason,
+ type Packet,
+ ServerOperation,
+ deserializePacket,
+ isServerPacket,
+ serializePacket,
+ uncapitalize,
+} from '@revanced/bot-shared'
+import type TypedEmitter from 'typed-emitter'
+import { type RawData, WebSocket } from 'ws'
+
+/**
+ * The class that handles the WebSocket connection to the server.
+ * This is the only relevant class for the time being. But in the future, there may be more classes to handle different protocols of the API.
+ */
+export class ClientWebSocketManager {
+ url: string
+ timeout: number
+
+ connecting = false
+ ready = false
+ disconnected: false | DisconnectReason = false
+ currentSequence = 0
+
+ #socket: WebSocket = null!
+ #emitter = new EventEmitter() as TypedEmitter
+
+ constructor(options: ClientWebSocketManagerOptions) {
+ this.url = options.url
+ this.timeout = options.timeout ?? 10000
+ }
+
+ /**
+ * Sets the URL to connect to
+ *
+ * **Requires a reconnect to take effect**
+ */
+ async setOptions({ url, timeout }: Partial, autoReconnect = true) {
+ if (url) this.url = url
+ this.timeout = timeout ?? this.timeout
+
+ if (autoReconnect) {
+ this.disconnect(true)
+ await this.connect()
+ }
+ }
+
+ /**
+ * Connects to the WebSocket API
+ * @returns A promise that resolves when the client is ready
+ */
+ async connect() {
+ if (this.connecting) throw new Error('Cannot connect when already connecting to the server')
+
+ this.connecting = true
+
+ await new Promise((rs, rj) => {
+ try {
+ this.#socket = new WebSocket(this.url)
+
+ const timeout = setTimeout(() => {
+ if (!this.ready) {
+ this.#socket?.close(DisconnectReason.TooSlow)
+ this._handleDisconnect(DisconnectReason.TooSlow, 'WebSocket connection was not readied in time')
+ }
+ }, this.timeout)
+
+ const closeBeforeReadyHandler = (code: number, reason: Buffer) => {
+ this._handleDisconnect(code, reason.toString())
+ cleanup()
+ }
+
+ const readyHandler = () => {
+ this.disconnected = false
+ cleanup()
+ this.#listen()
+ rs()
+ }
+
+ const socket = this.#socket
+ const cleanup = () => {
+ socket.off('open', readyHandler)
+ socket.off('close', closeBeforeReadyHandler)
+ clearTimeout(timeout)
+ }
+
+ this.#socket.on('open', readyHandler)
+ this.#socket.on('close', closeBeforeReadyHandler)
+ } catch (e) {
+ rj(e)
+ }
+ })
+ .then(() => {
+ this.#socket.on('close', (code, reason) => this._handleDisconnect(code, reason.toString()))
+ })
+ .finally(() => {
+ this.connecting = false
+ })
+ }
+
+ /**
+ * Adds an event listener
+ * @param name The event name to listen for
+ * @param handler The event handler
+ * @returns The event handler function
+ */
+ on(name: TOpName, handler: ClientWebSocketEvents[typeof name]) {
+ this.#emitter.on(name, handler)
+ }
+
+ /**
+ * Removes an event listener
+ * @param name The event name to remove a listener from
+ * @param handler The event handler to remove
+ * @returns The removed event handler function
+ */
+ off(name: TOpName, handler: ClientWebSocketEvents[typeof name]) {
+ this.#emitter.off(name, handler)
+ }
+
+ /**
+ * Adds an event listener that will only be called once
+ * @param name The event name to listen for
+ * @param handler The event handler
+ * @returns The event handler function
+ */
+ once(name: TOpName, handler: ClientWebSocketEvents[typeof name]) {
+ this.#emitter.once(name, handler)
+ }
+
+ /**
+ * Sends a packet to the server
+ * @param packet The packet to send
+ * @returns A promise that resolves when the packet has been sent
+ */
+ send(packet: Packet) {
+ this.#throwIfDisconnected('Cannot send a packet when already disconnected from the server')
+
+ this.currentSequence++
+
+ this.#socket.send(serializePacket(packet), err => {
+ if (err) throw err
+ })
+ }
+
+ /**
+ * Disconnects from the WebSocket API
+ */
+ disconnect(force?: boolean) {
+ if (!force) this.#throwIfDisconnected('Cannot disconnect when already disconnected from the server')
+ this._handleDisconnect(DisconnectReason.PlannedDisconnect)
+ }
+
+ /**
+ * Checks whether the client is ready
+ * @returns Whether the client is ready
+ */
+ isReady(): this is ReadiedClientWebSocketManager {
+ return this.ready
+ }
+
+ #listen() {
+ this.#socket.on('message', data => {
+ const packet = deserializePacket(this._toBuffer(data))
+
+ if (!isServerPacket(packet)) return this.#emitter.emit('invalidPacket', packet)
+
+ this.currentSequence = packet.s
+ this.#emitter.emit('packet', packet)
+
+ switch (packet.op) {
+ case ServerOperation.Hello: {
+ this.#emitter.emit('hello')
+ this.ready = true
+ this.#emitter.emit('ready')
+ break
+ }
+ case ServerOperation.Disconnect:
+ return this._handleDisconnect((packet as Packet).d.reason)
+ default:
+ return this.#emitter.emit(
+ uncapitalize(ServerOperation[packet.op] as ClientWebSocketEventName),
+ // @ts-expect-error: TS at it again
+ packet,
+ )
+ }
+ })
+ }
+
+ #throwIfDisconnected(errorMessage: string) {
+ if (this.disconnected !== false) throw new Error(errorMessage)
+ if (this.#socket.readyState !== this.#socket.OPEN) throw new Error(errorMessage)
+ }
+
+ protected _handleDisconnect(reason: DisconnectReason | number, message?: string) {
+ this.disconnected = reason in DisconnectReason ? reason : DisconnectReason.Generic
+ this.connecting = false
+ this.#socket?.close(reason)
+ this.#socket = null!
+
+ this.#emitter.emit('disconnect', reason, message)
+ }
+
+ protected _toBuffer(data: RawData) {
+ if (data instanceof Buffer) return data
+ if (data instanceof ArrayBuffer) return Buffer.from(data)
+ return Buffer.concat(data as Uint8Array[])
+ }
+}
+
+export interface ClientWebSocketManagerOptions {
+ /**
+ * The URL to connect to
+ */
+ url: string
+ /**
+ * The timeout for the connection
+ * @default 10000
+ */
+ timeout?: number
+}
+
+export type ClientWebSocketEventName = keyof typeof ServerOperation
+
+type ClientWebSocketPredefinedEvents = {
+ hello: () => Promise | void
+ ready: () => Promise | void
+ packet: (packet: Packet) => Promise | void
+ invalidPacket: (packet: Packet) => Promise | void
+ disconnect: (reason: DisconnectReason | number, message?: string) => Promise | void
+}
+
+export type ClientWebSocketEvents = {
+ [K in Exclude, keyof ClientWebSocketPredefinedEvents>]: (
+ packet: Packet<(typeof ServerOperation)[Capitalize]>,
+ ) => Promise | void
+} & ClientWebSocketPredefinedEvents
+
+export type ReadiedClientWebSocketManager = RequiredProperty>
diff --git a/packages/api/src/classes/index.ts b/packages/api/src/classes/index.ts
new file mode 100755
index 0000000..6762ec9
--- /dev/null
+++ b/packages/api/src/classes/index.ts
@@ -0,0 +1,3 @@
+export { default as Client } from './Client'
+export * from './Client'
+export * from './ClientWebSocket'
diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts
new file mode 100755
index 0000000..f50cdd7
--- /dev/null
+++ b/packages/api/src/index.ts
@@ -0,0 +1 @@
+export * from './classes'
diff --git a/packages/api/src/types.d.ts b/packages/api/src/types.d.ts
new file mode 100755
index 0000000..f0639d5
--- /dev/null
+++ b/packages/api/src/types.d.ts
@@ -0,0 +1,2 @@
+type RequiredProperty = { [P in keyof T]: Required> }
+type IfTrueElseNever = T extends true ? U : never
diff --git a/packages/api/tsconfig.json b/packages/api/tsconfig.json
new file mode 100755
index 0000000..1cd3a5f
--- /dev/null
+++ b/packages/api/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "extends": "../../tsconfig.packages.json",
+ "compilerOptions": {
+ "baseUrl": ".",
+ "rootDir": "./src",
+ "outDir": "dist",
+ "module": "ESNext",
+ "composite": true,
+ "noEmit": false
+ },
+ "include": ["src/**/*.ts"]
+}
diff --git a/packages/client/index.js b/packages/client/index.js
deleted file mode 100644
index 4488d7b..0000000
--- a/packages/client/index.js
+++ /dev/null
@@ -1,102 +0,0 @@
-import { Socket } from 'node:net';
-import { serialize, deserialize } from 'bson';
-import EventEmitter from 'node:events';
-
-class HelperClient extends EventEmitter {
- constructor({ server }) {
- super();
- if (!server?.port) throw new Error('You did not specify the server port.');
- this.server = server;
- this.client = new Socket();
- }
-
- connect() {
- this.client.connect(
- this.server.port,
- this.server.host ? this.server.host : 'localhost'
- );
-
- this.client.on('data', (data) => {
- const eventData = deserialize(data, {
- allowObjectSmallerThanBufferSize: true
- });
-
- switch (eventData.op) {
- case 2: {
- // The 'aiResponse' event.
-
- this.emit('aiResponse', eventData);
- break;
- }
-
- case 6: {
- // The 'ocrResponse' event.
-
- this.emit('ocrResponse', eventData);
- break;
- }
- }
- });
-
- this.client.on('connect', () => {
- if (this.reconnectionInterval) {
- clearInterval(this.reconnectionInterval);
- this.reconnectionInterval = null;
- }
-
- this.emit('connect');
- });
-
- this.client.on('close', () => {
- this.reconnectionInterval = setInterval(() => {
- this.client.connect(
- this.server.port,
- this.server.host ? this.server.host : 'localhost'
- );
- }, 5000);
- })
- }
-
- sendData(data) {
- this.client.write(serialize(data));
- return;
- }
-
- scanText(text, id) {
- this.sendData({
- op: 1,
- id,
- text
- });
-
- return;
- }
-
- scanImage(url, id) {
- this.sendData({
- op: 5,
- id,
- url
- });
-
- return;
- }
-
- sendTrainData(text, label) {
- this.sendData({
- op: 3,
- label,
- text
- });
-
- return;
- }
-
- trainAI() {
- this.sendData({ op: 4 });
-
- return;
- }
-}
-
-export default HelperClient;
diff --git a/packages/client/package-lock.json b/packages/client/package-lock.json
deleted file mode 100644
index 012ca1b..0000000
--- a/packages/client/package-lock.json
+++ /dev/null
@@ -1,117 +0,0 @@
-{
- "name": "helper-client",
- "version": "1.0.0",
- "lockfileVersion": 2,
- "requires": true,
- "packages": {
- "": {
- "name": "helper-client",
- "version": "1.0.0",
- "license": "GPL-3.0-or-later",
- "dependencies": {
- "bson": "^4.7.0"
- }
- },
- "node_modules/base64-js": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
- "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ]
- },
- "node_modules/bson": {
- "version": "4.7.0",
- "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.0.tgz",
- "integrity": "sha512-VrlEE4vuiO1WTpfof4VmaVolCVYkYTgB9iWgYNOrVlnifpME/06fhFRmONgBhClD5pFC1t9ZWqFUQEQAzY43bA==",
- "dependencies": {
- "buffer": "^5.6.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/buffer": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
- "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "dependencies": {
- "base64-js": "^1.3.1",
- "ieee754": "^1.1.13"
- }
- },
- "node_modules/ieee754": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
- "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ]
- }
- },
- "dependencies": {
- "base64-js": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
- "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
- },
- "bson": {
- "version": "4.7.0",
- "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.0.tgz",
- "integrity": "sha512-VrlEE4vuiO1WTpfof4VmaVolCVYkYTgB9iWgYNOrVlnifpME/06fhFRmONgBhClD5pFC1t9ZWqFUQEQAzY43bA==",
- "requires": {
- "buffer": "^5.6.0"
- }
- },
- "buffer": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
- "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
- "requires": {
- "base64-js": "^1.3.1",
- "ieee754": "^1.1.13"
- }
- },
- "ieee754": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
- "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
- }
- }
-}
diff --git a/packages/client/package.json b/packages/client/package.json
deleted file mode 100644
index 2824f83..0000000
--- a/packages/client/package.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "name": "@revanced-helper/helper-client",
- "version": "1.0.0",
- "description": "The ReVanced Helper client.",
- "main": "index.js",
- "type": "module",
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
- },
- "author": "Reis Can",
- "license": "GPL-3.0-or-later",
- "dependencies": {
- "bson": "^4.7.0"
- }
-}
\ No newline at end of file
diff --git a/packages/shared/LICENSE b/packages/shared/LICENSE
new file mode 100755
index 0000000..f288702
--- /dev/null
+++ b/packages/shared/LICENSE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/packages/shared/package.json b/packages/shared/package.json
new file mode 100755
index 0000000..aa9d2bd
--- /dev/null
+++ b/packages/shared/package.json
@@ -0,0 +1,38 @@
+{
+ "name": "@revanced/bot-shared",
+ "type": "module",
+ "version": "0.1.0",
+ "description": "🙌🏻 Shared components for bots assisting ReVanced",
+ "main": "dist/index.js",
+ "types": "dist/index.d.ts",
+ "scripts": {
+ "build": "bun bundle && bun types",
+ "watch": "conc --raw \"bun bundle:watch\" \"bun types:watch\"",
+ "bundle": "bun build src/index.ts --outdir=dist --sourcemap=external --target=bun --minify",
+ "bundle:watch": "bun run bundle --watch",
+ "types": "tsc --declaration --emitDeclarationOnly",
+ "types:watch": "bun types --watch --preserveWatchOutput",
+ "types:clean": "bun types --build --clean"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/revanced/revanced-bots.git",
+ "directory": "packages/shared"
+ },
+ "author": "Palm (https://palmdevs.me)",
+ "contributors": [
+ "Palm (https://palmdevs.me)",
+ "ReVanced (https://revanced.app)"
+ ],
+ "license": "GPL-3.0-or-later",
+ "bugs": {
+ "url": "https://github.com/revanced/revanced-bots/issues"
+ },
+ "homepage": "https://github.com/revanced/revanced-bots#readme",
+ "dependencies": {
+ "bson": "^6.10.3",
+ "chalk": "^5.4.1",
+ "tracer": "^1.3.0",
+ "valibot": "^0.30.0"
+ }
+}
diff --git a/packages/shared/src/constants/DisconnectReason.ts b/packages/shared/src/constants/DisconnectReason.ts
new file mode 100755
index 0000000..2276c21
--- /dev/null
+++ b/packages/shared/src/constants/DisconnectReason.ts
@@ -0,0 +1,39 @@
+/**
+ * Disconnect reasons for clients
+ */
+enum DisconnectReason {
+ /**
+ * The client disconnected on its own (**CLIENT-ONLY**)
+ */
+ PlannedDisconnect = 1000,
+ /**
+ * The client sent an invalid packet (unserializable or invalid JSON)
+ */
+ InvalidPacket = 1007,
+ /**
+ * The server has encountered an internal error
+ */
+ ServerError = 1011,
+ /**
+ * Unknown reason
+ */
+ Generic = 4000,
+ /**
+ * The client did not respond with a heartbeat in time
+ */
+ TimedOut = 4001,
+ /**
+ * The receiving end didn't have an open socket
+ */
+ NoOpenSocket = 4003,
+ /**
+ * The client connected from another location
+ */
+ NewConnection = 4004,
+ /**
+ * The client was not ready in time (**CLIENT-ONLY**)
+ */
+ TooSlow = 4012,
+}
+
+export default DisconnectReason
diff --git a/packages/shared/src/constants/HumanizedDisconnectReason.ts b/packages/shared/src/constants/HumanizedDisconnectReason.ts
new file mode 100755
index 0000000..881d03d
--- /dev/null
+++ b/packages/shared/src/constants/HumanizedDisconnectReason.ts
@@ -0,0 +1,18 @@
+import DisconnectReason from './DisconnectReason'
+
+/**
+ * Humanized disconnect reasons for logs
+ */
+const HumanizedDisconnectReason = {
+ [1006]: 'the receiving end had unexpectedly closed the connection',
+ [DisconnectReason.InvalidPacket]: 'the client has sent invalid packet',
+ [DisconnectReason.Generic]: '(unknown reason)',
+ [DisconnectReason.TimedOut]: 'the client did not respond with a heartbeat in time',
+ [DisconnectReason.ServerError]: 'the server had an internal server error',
+ [DisconnectReason.TooSlow]: 'the client was not ready in time',
+ [DisconnectReason.PlannedDisconnect]: 'the client has disconnected on its own',
+ [DisconnectReason.NoOpenSocket]: 'the receiving end did not have an open socket',
+ [DisconnectReason.NewConnection]: 'the client connected from another location',
+} as const satisfies Record
+
+export default HumanizedDisconnectReason
diff --git a/packages/shared/src/constants/Operation.ts b/packages/shared/src/constants/Operation.ts
new file mode 100755
index 0000000..d3104ad
--- /dev/null
+++ b/packages/shared/src/constants/Operation.ts
@@ -0,0 +1,60 @@
+/**
+ * Client operation codes for the gateway
+ */
+export enum ClientOperation {
+ /**
+ * Client's request to parse text
+ */
+ ParseText = 100,
+ /**
+ * Client's request to parse image
+ */
+ ParseImage = 101,
+ /**
+ * Client's request to train a message
+ */
+ TrainMessage = 102,
+}
+
+/**
+ * Server operation codes for the gateway
+ */
+export enum ServerOperation {
+ /**
+ * Server's initial response to a client's connection
+ */
+ Hello = 1,
+
+ /**
+ * Server's response to client's request to parse text
+ */
+ ParsedText = 10,
+ /**
+ * Server's response to client's request to parse image
+ */
+ ParsedImage = 11,
+ /**
+ * Server's failure response to client's request to parse text
+ */
+ ParseTextFailed = 12,
+ /**
+ * Server's failure response to client's request to parse image
+ */
+ ParseImageFailed = 13,
+ /**
+ * Server's response to client's request to train a message
+ */
+ TrainedMessage = 14,
+ /**
+ * Server's failure response to client's request to train a message
+ */
+ TrainMessageFailed = 15,
+
+ /**
+ * Server's disconnect message
+ */
+ Disconnect = 20,
+}
+
+export const Operation = { ...ClientOperation, ...ServerOperation } as const
+export type Operation = ClientOperation | ServerOperation
diff --git a/packages/shared/src/constants/index.ts b/packages/shared/src/constants/index.ts
new file mode 100755
index 0000000..a353663
--- /dev/null
+++ b/packages/shared/src/constants/index.ts
@@ -0,0 +1,3 @@
+export { default as DisconnectReason } from './DisconnectReason'
+export { default as HumanizedDisconnectReason } from './HumanizedDisconnectReason'
+export * from './Operation'
diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts
new file mode 100755
index 0000000..8d84460
--- /dev/null
+++ b/packages/shared/src/index.ts
@@ -0,0 +1,3 @@
+export * from './constants'
+export * from './schemas'
+export * from './utils'
diff --git a/packages/shared/src/schemas/Packet.ts b/packages/shared/src/schemas/Packet.ts
new file mode 100755
index 0000000..757cfef
--- /dev/null
+++ b/packages/shared/src/schemas/Packet.ts
@@ -0,0 +1,93 @@
+import {
+ url,
+ type AnySchema,
+ type BooleanSchema,
+ type NullSchema,
+ type ObjectSchema,
+ type Output,
+ array,
+ boolean,
+ enum_,
+ null_,
+ object,
+ parse,
+ special,
+ string,
+ // merge
+} from 'valibot'
+import DisconnectReason from '../constants/DisconnectReason'
+import { ClientOperation, Operation, ServerOperation } from '../constants/Operation'
+
+/**
+ * Schema to validate packets
+ */
+export const PacketSchema = special(input => {
+ if (
+ typeof input === 'object' &&
+ input &&
+ 'op' in input &&
+ typeof input.op === 'number' &&
+ input.op in Operation &&
+ 'd' in input
+ ) {
+ if (input.op in ServerOperation && !('s' in input && typeof input.s === 'number')) return false
+
+ try {
+ parse(PacketDataSchemas[input.op as Operation], input.d)
+ return true
+ } catch {
+ return false
+ }
+ }
+ return false
+}, 'Invalid packet data')
+
+/**
+ * Schema to validate packet data for each possible operations
+ */
+export const PacketDataSchemas = {
+ [ServerOperation.Hello]: null_(),
+ [ServerOperation.ParsedText]: object({
+ labels: array(
+ object({
+ name: string(),
+ confidence: special(input => typeof input === 'number' && input >= 0 && input <= 1),
+ }),
+ ),
+ }),
+ [ServerOperation.ParsedImage]: object({
+ text: string(),
+ }),
+ [ServerOperation.ParseTextFailed]: null_(),
+ [ServerOperation.ParseImageFailed]: null_(),
+ [ServerOperation.Disconnect]: object({
+ reason: enum_(DisconnectReason),
+ }),
+ [ServerOperation.TrainedMessage]: boolean(),
+ [ServerOperation.TrainMessageFailed]: null_(),
+
+ [ClientOperation.ParseText]: object({
+ text: string(),
+ }),
+ [ClientOperation.ParseImage]: object({
+ image_url: string([url()]),
+ }),
+ [ClientOperation.TrainMessage]: object({
+ text: string(),
+ label: string(),
+ }),
+} as const satisfies Record<
+ Operation,
+ // biome-ignore lint/suspicious/noExplicitAny: This is a schema, it's not possible to type it
+ ObjectSchema | AnySchema | NullSchema | BooleanSchema
+>
+
+export type Packet = TOp extends ServerOperation
+ ? PacketWithSequenceNumber
+ : Omit, 's'>
+
+type PacketWithSequenceNumber = {
+ op: TOp
+ d: Output<(typeof PacketDataSchemas)[TOp]>
+ s: number
+}
diff --git a/packages/shared/src/schemas/index.ts b/packages/shared/src/schemas/index.ts
new file mode 100755
index 0000000..e23a5a9
--- /dev/null
+++ b/packages/shared/src/schemas/index.ts
@@ -0,0 +1 @@
+export * from './Packet'
diff --git a/packages/shared/src/utils/environment.ts b/packages/shared/src/utils/environment.ts
new file mode 100644
index 0000000..b0c1d61
--- /dev/null
+++ b/packages/shared/src/utils/environment.ts
@@ -0,0 +1,13 @@
+export function getMissingEnvironmentVariables(keys: string[]) {
+ return keys.filter(key => !process.env[key])
+}
+
+export function getEnvironmentType() {
+ const environmentValue = process.env['NODE_ENV']
+ // @ts-expect-error https://github.com/microsoft/TypeScript/issues/26255
+ if (!NodeEnvironments.includes(environmentValue)) return null
+ return process.env['NODE_ENV'] as NodeEnvironment
+}
+
+const NodeEnvironments = ['development', 'production'] as const
+export type NodeEnvironment = (typeof NodeEnvironments)[number]
diff --git a/packages/shared/src/utils/guard.ts b/packages/shared/src/utils/guard.ts
new file mode 100755
index 0000000..91825cb
--- /dev/null
+++ b/packages/shared/src/utils/guard.ts
@@ -0,0 +1,30 @@
+import { ClientOperation, type Operation, ServerOperation } from '../constants/Operation'
+import type { Packet } from '../schemas/Packet'
+
+/**
+ * Checks whether a packet is trying to do the given operation
+ * @param op Operation code to check
+ * @param packet A packet
+ * @returns Whether this packet is trying to do the operation given
+ */
+export function packetMatchesOperation(op: TOp, packet: Packet): packet is Packet {
+ return packet.op === op
+}
+
+/**
+ * Checks whether this packet is a client packet **(this does NOT validate the data)**
+ * @param packet A packet
+ * @returns Whether this packet is a client packet
+ */
+export function isClientPacket(packet: Packet): packet is Packet {
+ return packet.op in ClientOperation
+}
+
+/**
+ * Checks whether this packet is a server packet **(this does NOT validate the data or the sequence number)**
+ * @param packet A packet
+ * @returns Whether this packet is a server packet
+ */
+export function isServerPacket(packet: Packet): packet is Packet {
+ return packet.op in ServerOperation
+}
diff --git a/packages/shared/src/utils/index.ts b/packages/shared/src/utils/index.ts
new file mode 100755
index 0000000..7b06030
--- /dev/null
+++ b/packages/shared/src/utils/index.ts
@@ -0,0 +1,5 @@
+export * from './environment'
+export * from './guard'
+export * from './logger'
+export * from './serialization'
+export * from './string'
diff --git a/packages/shared/src/utils/logger.ts b/packages/shared/src/utils/logger.ts
new file mode 100644
index 0000000..deeb19d
--- /dev/null
+++ b/packages/shared/src/utils/logger.ts
@@ -0,0 +1,38 @@
+import { Chalk, supportsColor, supportsColorStderr } from 'chalk'
+import { type Tracer, colorConsole, console as uncoloredConsole } from 'tracer'
+
+const chalk = new Chalk()
+const DefaultConfig = {
+ dateformat: 'dd/mm/yyyy HH:mm:ss.sss Z',
+ format: [
+ '{{message}}',
+ {
+ error: `${chalk.bgRedBright.whiteBright(' ERROR ')} {{message}}\n${chalk.gray('{{stack}}')}`,
+ debug: chalk.gray('DEBUG: {{message}}'),
+ warn: `${chalk.bgYellowBright.whiteBright(' WARN ')} ${chalk.yellowBright('{{message}}')}`,
+ info: `${chalk.bgBlueBright.whiteBright(' INFO ')} ${chalk.cyanBright('{{message}}')}`,
+ fatal: `${chalk.bgRedBright.whiteBright(' FATAL ')} ${chalk.redBright('{{message}}')}\n${chalk.white(
+ '{{stack}}',
+ )}`,
+ log: '{{message}}',
+ },
+ ],
+ methods: ['debug', 'log', 'info', 'warn', 'error', 'fatal'],
+ filters: [],
+} satisfies Tracer.LoggerConfig
+
+export function createLogger(config?: Omit) {
+ const combinedConfig = { ...DefaultConfig, ...config }
+
+ if (
+ // biome-ignore lint/complexity/useOptionalChain: No Biome, this isn't a nullable check
+ supportsColor &&
+ supportsColor.hasBasic &&
+ supportsColorStderr &&
+ supportsColorStderr.hasBasic
+ )
+ return colorConsole(combinedConfig)
+ return uncoloredConsole(combinedConfig)
+}
+
+export type Logger = ReturnType
diff --git a/packages/shared/src/utils/serialization.ts b/packages/shared/src/utils/serialization.ts
new file mode 100755
index 0000000..5f9ba26
--- /dev/null
+++ b/packages/shared/src/utils/serialization.ts
@@ -0,0 +1,23 @@
+import * as BSON from 'bson'
+import { parse } from 'valibot'
+import type { Operation } from '../constants'
+import { type Packet, PacketSchema } from '../schemas'
+
+/**
+ * Compresses a packet into a buffer
+ * @param packet The packet to compress
+ * @returns A buffer of the compressed packet
+ */
+export function serializePacket(packet: Packet) {
+ return BSON.serialize(packet)
+}
+
+/**
+ * Decompresses a buffer into a packet
+ * @param buffer The buffer to decompress
+ * @returns A packet
+ */
+export function deserializePacket(buffer: Buffer) {
+ const data = BSON.deserialize(buffer as Uint8Array)
+ return parse(PacketSchema, data) as Packet
+}
diff --git a/packages/shared/src/utils/string.ts b/packages/shared/src/utils/string.ts
new file mode 100755
index 0000000..e7e805e
--- /dev/null
+++ b/packages/shared/src/utils/string.ts
@@ -0,0 +1,8 @@
+/**
+ * Uncapitalizes the first letter of a string
+ * @param str The string to uncapitalize
+ * @returns The uncapitalized string
+ */
+export function uncapitalize(str: T): Uncapitalize {
+ return (str.charAt(0).toLowerCase() + str.slice(1)) as Uncapitalize
+}
diff --git a/packages/shared/tsconfig.json b/packages/shared/tsconfig.json
new file mode 100755
index 0000000..1cd3a5f
--- /dev/null
+++ b/packages/shared/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "extends": "../../tsconfig.packages.json",
+ "compilerOptions": {
+ "baseUrl": ".",
+ "rootDir": "./src",
+ "outDir": "dist",
+ "module": "ESNext",
+ "composite": true,
+ "noEmit": false
+ },
+ "include": ["src/**/*.ts"]
+}
diff --git a/patches/@semantic-release%2Fnpm@12.0.1.patch b/patches/@semantic-release%2Fnpm@12.0.1.patch
new file mode 100644
index 0000000..7176bff
--- /dev/null
+++ b/patches/@semantic-release%2Fnpm@12.0.1.patch
@@ -0,0 +1,69 @@
+diff --git a/node_modules/@semantic-release/npm/.bun-tag-3853154e196b7721 b/.bun-tag-3853154e196b7721
+new file mode 100644
+index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
+diff --git a/node_modules/@semantic-release/npm/.bun-tag-550461f23a8ec245 b/.bun-tag-550461f23a8ec245
+new file mode 100644
+index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
+diff --git a/node_modules/@semantic-release/npm/.bun-tag-c9c8130945517add b/.bun-tag-c9c8130945517add
+new file mode 100644
+index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
+diff --git a/lib/prepare.js b/lib/prepare.js
+index 3e76bec44cf595a1b4141728336bed904d4d518d..4b25ca64879bbee2a600f2b23b738c86136ad9c6 100644
+--- a/lib/prepare.js
++++ b/lib/prepare.js
+@@ -1,6 +1,7 @@
+ import path from "path";
+-import { move } from "fs-extra";
++import { rename, readFile, writeFile } from "fs/promises";
+ import { execa } from "execa";
++import detectIndent from 'detect-indent';
+
+ export default async function (
+ npmrc,
+@@ -11,19 +12,13 @@ export default async function (
+
+ logger.log("Write version %s to package.json in %s", version, basePath);
+
+- const versionResult = execa(
+- "npm",
+- ["version", version, "--userconfig", npmrc, "--no-git-tag-version", "--allow-same-version"],
+- {
+- cwd: basePath,
+- env,
+- preferLocal: true,
+- }
+- );
+- versionResult.stdout.pipe(stdout, { end: false });
+- versionResult.stderr.pipe(stderr, { end: false });
++ const pkgJsonPath = path.join(basePath, 'package.json')
++ const pkgJsonRaw = (await readFile(pkgJsonPath)).toString()
++ const pkgJson = JSON.parse(pkgJsonRaw)
++ pkgJson.version = version
+
+- await versionResult;
++ await writeFile(pkgJsonPath, JSON.stringify(pkgJson, null, detectIndent(pkgJsonRaw).indent))
++ await execa("bun", ["install"]);
+
+ if (tarballDir) {
+ logger.log("Creating npm package version %s", version);
+@@ -38,7 +33,7 @@ export default async function (
+ // Only move the tarball if we need to
+ // Fixes: https://github.com/semantic-release/npm/issues/169
+ if (tarballSource !== tarballDestination) {
+- await move(tarballSource, tarballDestination);
++ await rename(tarballSource, tarballDestination);
+ }
+ }
+ }
+diff --git a/package.json b/package.json
+index e716bf6b35130c168ab7c4babc89a0346aacc9ad..e372de1ca5967509a6769db88ff967e1039b03ac 100644
+--- a/package.json
++++ b/package.json
+@@ -21,6 +21,7 @@
+ "dependencies": {
+ "@semantic-release/error": "^4.0.0",
+ "aggregate-error": "^5.0.0",
++ "detect-indent": "^7.0.1",
+ "execa": "^9.0.0",
+ "fs-extra": "^11.0.0",
+ "lodash-es": "^4.17.21",
diff --git a/patches/decancer@3.2.4.patch b/patches/decancer@3.2.4.patch
new file mode 100644
index 0000000..a5408e4
--- /dev/null
+++ b/patches/decancer@3.2.4.patch
@@ -0,0 +1,13 @@
+diff --git a/src/lib.js b/src/lib.js
+index de45d7dbe82975b09eff3742d0718accae2107fc..0575daa03dfabdd5c96928458ff4270cb8f7188a 100644
+--- a/src/lib.js
++++ b/src/lib.js
+@@ -42,7 +42,7 @@ function isMusl() {
+ }
+
+ function getBinding(name) {
+- const path = join(__dirname, '..', `decancer.${name}.node`)
++ const path = join(import.meta.dir, '..', `decancer.${name}.node`)
+
+ return require(existsSync(path) ? path : `@vierofernando/decancer-${name}`)
+ }
diff --git a/patches/drizzle-kit@0.22.8.patch b/patches/drizzle-kit@0.22.8.patch
new file mode 100644
index 0000000..5571348
--- /dev/null
+++ b/patches/drizzle-kit@0.22.8.patch
@@ -0,0 +1,21 @@
+diff --git a/bin.cjs b/bin.cjs
+index 142ed9c20f28dc1080bebfb52325fa308c6cb771..9d3bea0787f6c05df11567c6821bc85743286340 100644
+--- a/bin.cjs
++++ b/bin.cjs
+@@ -22053,7 +22053,7 @@ var init_sqliteImports = __esm({
+ const { unregister } = await safeRegister();
+ for (let i2 = 0; i2 < imports.length; i2++) {
+ const it = imports[i2];
+- const i0 = require(`${it}`);
++ const i0 = await import(`${it}`);
+ const prepared = prepareFromExports3(i0);
+ tables.push(...prepared.tables);
+ }
+@@ -129572,6 +129572,7 @@ var generateCommand = new Command("generate").option("--dialect ", "Dat
+ } else {
+ assertUnreachable(dialect7);
+ }
++ process.exit(0);
+ });
+ var migrateCommand = new Command("migrate").option(
+ "--config ",
diff --git a/semantic-release-config.js b/semantic-release-config.js
new file mode 100644
index 0000000..a834cdc
--- /dev/null
+++ b/semantic-release-config.js
@@ -0,0 +1,75 @@
+// @ts-check
+
+/**
+ * @type {import('semantic-release').Options}
+ */
+const Options = {
+ branches: [
+ 'main',
+ {
+ name: 'dev',
+ prerelease: true,
+ },
+ ],
+ plugins:
+ process.env['RELEASE_WORKFLOW_STEP'] !== 'publish'
+ ? [
+ [
+ '@semantic-release/commit-analyzer',
+ {
+ releaseRules: [{ type: 'build', scope: 'Needs bump', release: 'patch' }],
+ },
+ ],
+ '@semantic-release/release-notes-generator',
+ '@semantic-release/changelog',
+ [
+ '@semantic-release/npm',
+ {
+ npmPublish: false,
+ },
+ ],
+ [
+ '@semantic-release/git',
+ {
+ assets: ['CHANGELOG.md', 'package.json', '../../bun.lockb'],
+ },
+ ],
+ [
+ '@semantic-release/github',
+ {
+ assets: [
+ {
+ path: 'dist/*',
+ },
+ ],
+ successComment: false,
+ },
+ ],
+ // This unfortunately has to run multiple times, even though it needs to run only once.
+ [
+ '@saithodev/semantic-release-backmerge',
+ {
+ backmergeBranches: [
+ {
+ from: 'main',
+ to: 'dev',
+ },
+ ],
+ clearWorkspace: true,
+ },
+ ],
+ ]
+ : [],
+}
+
+/**
+ * @param {import('semantic-release').Options} subprojectOptions
+ * @returns {import('semantic-release').Options}
+ */
+export default function defineSubprojectReleaseConfig(subprojectOptions) {
+ return {
+ ...Options,
+ ...subprojectOptions,
+ plugins: [...(subprojectOptions.plugins || []), ...(Options.plugins || [])],
+ }
+}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..3280e50
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,27 @@
+{
+ "extends": ["@tsconfig/strictest"],
+ "compilerOptions": {
+ "lib": ["ESNext"],
+ "target": "ESNext",
+ "module": "ESNext",
+ "moduleResolution": "Bundler",
+
+ "strict": true,
+ "skipLibCheck": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true,
+ "useUnknownInCatchVariables": true,
+ "noPropertyAccessFromIndexSignature": true,
+
+ "noEmitOnError": true,
+ "resolveJsonModule": true,
+ "esModuleInterop": true,
+ "declaration": false,
+ "allowSyntheticDefaultImports": true,
+ "isolatedModules": true,
+ "allowImportingTsExtensions": false
+ },
+ "include": ["./**/*"],
+ "exclude": ["./packages/**/*"]
+}
diff --git a/tsconfig.packages.json b/tsconfig.packages.json
new file mode 100644
index 0000000..f900901
--- /dev/null
+++ b/tsconfig.packages.json
@@ -0,0 +1,16 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "declaration": true,
+ "declarationMap": true
+ },
+ "references": [
+ {
+ "path": "./packages/shared"
+ },
+ {
+ "path": "./packages/api"
+ }
+ ],
+ "exclude": ["**/node_modules", "**/dist"]
+}
diff --git a/turbo.json b/turbo.json
new file mode 100755
index 0000000..b31dd44
--- /dev/null
+++ b/turbo.json
@@ -0,0 +1,14 @@
+{
+ "$schema": "https://turbo.build/schema.json",
+ "tasks": {
+ "build": {
+ "dependsOn": ["^build"],
+ "outputs": ["dist/**"],
+ "outputLogs": "errors-only"
+ },
+ "watch": {
+ "dependsOn": ["^watch"],
+ "outputLogs": "errors-only"
+ }
+ }
+}